Auth0 Integration
Auth0 Integration
Section titled “Auth0 Integration”Auth0 is a cloud identity platform that handles authentication and authorization. This guide shows how to protect your Tabula Lens endpoint with Auth0 JWT validation and pass an access token from the frontend.
Prerequisites
Section titled “Prerequisites”Auth0 Dashboard setup
Section titled “Auth0 Dashboard setup”Before writing any code, configure the following in your Auth0 Dashboard:
- Create an Application — choose Single Page Application for React frontends or Regular Web App for server-rendered apps. Note the Domain and Client ID.
- Create an API — give it an identifier (this becomes your
audience). Note the API identifier.
Install packages
Section titled “Install packages”Backend (Express):
npm i express-oauth2-jwt-bearerpnpm add express-oauth2-jwt-beareryarn add express-oauth2-jwt-bearerBackend (Next.js):
npm i @auth0/nextjs-auth0pnpm add @auth0/nextjs-auth0yarn add @auth0/nextjs-auth0Frontend:
npm i @auth0/auth0-reactpnpm add @auth0/auth0-reactyarn add @auth0/auth0-reactEnvironment variables
Section titled “Environment variables”# BackendAUTH0_DOMAIN=your-tenant.auth0.comAUTH0_AUDIENCE=https://your-api-identifier
# FrontendNEXT_PUBLIC_AUTH0_DOMAIN=your-tenant.auth0.comNEXT_PUBLIC_AUTH0_CLIENT_ID=your-client-idNEXT_PUBLIC_AUTH0_AUDIENCE=https://your-api-identifierBackend Setup
Section titled “Backend Setup”Express
Section titled “Express”Use express-oauth2-jwt-bearer to validate the JWT before forwarding the request to Tabula Lens:
import express from 'express';import { auth } from 'express-oauth2-jwt-bearer';import { TabulaLens, expressAdapter } from '@tabula-lens/node';
const app = express();const tabulaLens = new TabulaLens(process.env.DATABASE_URL!);
// Configure JWT validation — JWKS is fetched automatically from Auth0const checkJwt = auth({ issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`, audience: process.env.AUTH0_AUDIENCE,});
// Protect the Tabula Lens endpointapp.use('/api/tabula-lens', checkJwt, expressAdapter(tabulaLens));
// Handle JWT validation errorsapp.use((err, req, res, next) => { if (err.name === 'UnauthorizedError') { return res.status(401).json({ error: 'Invalid token' }); } next(err);});Next.js App Router
Section titled “Next.js App Router”Use the official @auth0/nextjs-auth0 SDK to protect the route:
import { handleAuth } from '@auth0/nextjs-auth0';
export const GET = handleAuth();import { withApiAuthRequired } from '@auth0/nextjs-auth0';import { TabulaLens, createNextRouteHandler } from '@tabula-lens/node';
const tabulaLens = new TabulaLens(process.env.DATABASE_URL!);const handler = createNextRouteHandler(tabulaLens);
export const GET = withApiAuthRequired(async function (request: Request) { return handler(request);});Frontend Integration
Section titled “Frontend Integration”Wrap your app with Auth0Provider, then use getAccessTokenSilently to retrieve a token for each request:
// app/layout.tsx (or your root component)import { Auth0Provider } from '@auth0/auth0-react';
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <Auth0Provider domain={process.env.NEXT_PUBLIC_AUTH0_DOMAIN!} clientId={process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID!} authorizationParams={{ redirect_uri: typeof window !== 'undefined' ? window.location.origin : '', audience: process.env.NEXT_PUBLIC_AUTH0_AUDIENCE, }} > {children} </Auth0Provider> );}'use client';import { useAuth0 } from '@auth0/auth0-react';import { DatabaseViewer } from '@tabula-lens/react';
export function TabulaLensViewer() { const { getAccessTokenSilently, isAuthenticated, isLoading } = useAuth0();
if (isLoading) return <div>Loading...</div>; if (!isAuthenticated) return <div>Sign in to view data</div>;
return ( <DatabaseViewer path="/api/tabula-lens" getAuthHeaders={async () => { const token = await getAccessTokenSilently(); return { Authorization: `Bearer ${token}` }; }} /> );}Important Notes
Section titled “Important Notes”audiencemust match exactly — theaudiencevalue on both the backend and frontend must be identical to the API identifier in your Auth0 Dashboard. A mismatch causes JWT validation to fail.- JWKS is automatic —
express-oauth2-jwt-bearerfetches public keys fromhttps://YOUR_DOMAIN/.well-known/jwks.jsonat startup. No manual key configuration is needed. - Token refresh is automatic —
getAccessTokenSilently()silently refreshes expired tokens using a refresh token or the Auth0 session. Each call togetAuthHeaderswill always yield a valid token. - RS256 by default — Auth0 signs tokens with RS256 (asymmetric). Do not switch to HS256 unless you have a specific reason, as RS256 is more secure for public clients.
audiencescope — if you need to request specific scopes (e.g.read:database), add them toauthorizationParams.scopein the provider and enforce them on the backend withrequiredScopes.