在向 Express 或 Node.js API 添加 Auth0 令牌验证时使用 -集成 express-oauth2-jwt-bearer SDK,以 JWT Bearer 方式保护 Node.js API 端点
The express-oauth2-jwt-bearer package provides Express middleware for validating Auth0 JWT Bearer access tokens. It handles token extraction, signature verification, audience and issuer validation, and expiry checks per RFC 6750 — letting you focus on business logic rather than JWT parsing.
Agent instruction: Before providing SDK setup instructions, fetch the latest release version by running:
bash
gh api repos/auth0/node-oauth2-jwt-bearer/releases/latest --jq '.tag_name'Use the returned version in all
package.jsondependency lines instead of any hardcoded version below.
npm install -g @auth0/auth0-cliUse CaseRecommended SkillBuilding a server-side web app with login UI (Express sessions)auth0-expressBuilding a Next.js app with server-side authauth0-nextjsBuilding a React/Angular/Vue SPAauth0-react, auth0-angular, auth0-vueBuilding a React Native or mobile appauth0-react-native, auth0-android, auth0-swiftASP.NET Core Web APIauth0-aspnetcore-apiGo API with JWT middlewarego-jwt-middlewarePython API (Flask/FastAPI)auth0-api-pythonNode.js API using the older express-jwt packageexpress-jwt
Agent instruction: Follow these steps to integrate
express-oauth2-jwt-bearerinto the user's Node.js API project.
Fetch latest version (see instruction above).
Install the SDK: bash
npm install express-oauth2-jwt-bearerConfigure Auth0 — follow
references/setup.md. If the user already provided their Auth0 Domain and API Audience in the prompt, use them directly — skip the bootstrap script and do NOT callAskUserQuestionto re-confirm. Otherwise, offer automatic setup via bootstrap script or manual setup.Set up middleware — add to
app.jsorserver.js: javascriptimport { auth } from 'express-oauth2-jwt-bearer'; const checkJwt = auth({ issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`, audience: process.env.AUTH0_AUDIENCE, }); app.use(checkJwt); // apply globally, or per-routeProtect endpoints — apply middleware globally or to specific routes: javascript
// Global protection app.use(checkJwt); // Or per-route app.get('/api/private', checkJwt, (req, res) => { res.json({ sub: req.auth.payload.sub }); });Add RBAC (optional) — use
requiredScopes()orclaimIncludes()for permission-based access: javascriptimport { auth, requiredScopes, claimIncludes } from 'express-oauth2-jwt-bearer'; app.get('/api/messages', checkJwt, requiredScopes('read:messages'), (req, res) => { res.json({ messages: [] }); });Important:
requiredScopesaccepts a single argument — a space-separated string or an array. Do NOT pass multiple string arguments:requiredScopes('read:msg', 'write:msg')silently ignores everything after the first. UserequiredScopes('read:msg write:msg')orrequiredScopes(['read:msg', 'write:msg'])instead.Verify the integration — build and test: bash
node server.js curl http://localhost:3000/api/private # should return 401 curl -H "Authorization: Bearer <token>" http://localhost:3000/api/private # should return 200Failcheck: If the server fails to start or tokens are rejected unexpectedly, check
references/api.mdfor common issues. After 5-6 failed iterations, useAskUserQuestionto ask the user for more details about their environment.
MistakeSymptomFixCreated an Application instead of an API in Auth0 DashboardToken validation fails; wrong audienceCreate a new API (Resource Server) in Auth0 Dashboard → APIsAudience doesn't match API identifier exactly401 Unauthorized — "Audience mismatch"Copy the exact API Identifier string from Auth0 Dashboard → APIsDomain includes https:// prefixError: Invalid URL at startupUse hostname only: your-tenant.us.auth0.com, not https://...Checking scope claim instead of permissions for RBAC403 always returned or permissions ignoredUse requiredScopes() for scope-based RBAC; use claimIncludes('permissions', 'read:data') for Auth0 RBAC permission claimsCORS not configured before auth middlewarePreflight OPTIONS requests return 401Add cors() middleware before auth() in the middleware chain.env file not loadedundefined for domain/audienceAdd import 'dotenv/config' at the top of the entry filereq.auth is undefinedTypeError: Cannot read properties of undefinedVerify checkJwt middleware runs before the handler
FunctionDescriptionReturnsauth(options?)JWT Bearer validation middlewareHandler — 401 if token invalid/missingrequiredScopes(scopes)Validates token has all required scopesHandler — 403 if scopes missingscopeIncludesAny(scopes)Validates token has at least one scopeHandler — 403 if no matchclaimEquals(claim, value)Validates a claim equals a valueHandler — 401 if mismatchclaimIncludes(claim, ...values)Validates claim includes all valuesHandler — 401 if incompleteclaimCheck(fn, desc?)Custom claim validation functionHandler — 401 if fn returns false
OptionTypeDescriptionissuerBaseURL``stringAuth0 domain with https:// (required unless using env vars)audience``stringAPI Identifier from Auth0 Dashboard (required unless using env vars)tokenSigningAlg``stringSigning algorithm (default: RS256; use HS256 for symmetric)authRequired``booleanSet false to make authentication optional (default: true)clockTolerance``numberClock skew tolerance in seconds (no default; undefined unless set)dpop``DPoPOptionsDPoP configuration (see integration.md)
VariableDescriptionISSUER_BASE_URLAuth0 domain with https:// (auto-detected by SDK)AUDIENCEAPI Identifier (auto-detected by SDK)
After successful validation, req.auth contains:
typescript
req.auth.payload // Decoded JWT payload (sub, iss, aud, exp, permissions, etc.)
req.auth.header // JWT header (alg, typ, kid)
req.auth.token // Raw JWT string
The node-oauth2-jwt-bearer monorepo contains three packages:
PackagePurposeexpress-oauth2-jwt-bearerMain package. Express middleware for JWT Bearer validation. Published to npm.access-token-jwtLow-level JWT verification utilities (used internally).oauth2-bearerRFC 6750 Bearer token extraction (used internally).
In practice, you only install and import express-oauth2-jwt-bearer.
Auth PatternSDKWhen to UseJWT Bearer (stateless)express-oauth2-jwt-bearerAPIs called by SPAs, mobile apps, M2M clientsSession-based (stateful)@auth0/express-openid-connectWeb apps with login UI and server-side sessions
bash
# Get test token from Auth0 Dashboard → APIs → your API → Test tab
# Copy the token, then:
# 1. Verify 401 on protected route (no token)
curl -v http://localhost:3000/api/private
# 2. Verify 200 with valid token
curl -H "Authorization: Bearer <paste-token-here>" http://localhost:3000/api/private
# 3. Verify 403 with valid token but missing scope
curl -H "Authorization: Bearer <paste-token-here>" http://localhost:3000/api/admin
# 4. Verify CORS preflight
curl -v -X OPTIONS http://localhost:3000/api/private \
-H "Origin: http://localhost:5173" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: Authorization"