npx skills add ...
npx skills add auth0/agent-skills --skill express-oauth2-jwt-bearer
npx skills add auth0/agent-skills --skill express-oauth2-jwt-bearer
Use when protecting Express or Node.js API endpoints with JWT Bearer token validation, scope-based access control, or DPoP binding. Integrates express-oauth2-jwt-bearer — use even if the user says "validate tokens in my Express API" or "protect my Node.js API endpoints".
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:
Use the returned version in all
package.jsondependency lines instead of any hardcoded version below.
npm install -g @auth0/auth0-cli| Use Case | Recommended Skill |
|---|---|
| Building a server-side web app with login UI (Express sessions) | auth0-express |
| Building a Next.js app with server-side auth | auth0-nextjs |
| Building a React/Angular/Vue SPA | auth0-react, auth0-angular, auth0-vue |
| Building a React Native or mobile app | auth0-react-native, auth0-android, auth0-swift |
| ASP.NET Core Web API | auth0-aspnetcore-api |
| Go API with JWT middleware | go-jwt-middleware |
| Python API (Flask/FastAPI) | auth0-api-python |
Node.js API using the older express-jwt package | express-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:
Configure Auth0 — follow
references/setup.md. If the user already provided their Auth0 Domain and API Audience in the prompt, write them to a.envfile asISSUER_BASE_URL(the full issuer URL, includinghttps://) andAUDIENCE— the SDK reads these automatically. Skip the bootstrap script and do NOT callAskUserQuestionto re-confirm. Never hardcode the domain or audience as literal strings (or||fallback defaults) inserver.js/app.js— they belong in.envonly. Otherwise, offer automatic setup via bootstrap script or manual setup.Set up middleware — first create a
.envfile with the Auth0 values, then load it and add the middleware.express-oauth2-jwt-bearerreadsISSUER_BASE_URLandAUDIENCEfrom the environment automatically, soauth()needs no arguments:Keep the issuer and audience in
.env— do not inline literal values or pass them as arguments here.Protect endpoints — apply middleware globally or to specific routes:
Add RBAC (optional) — use
requiredScopes()orclaimIncludes()for permission-based access: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:
Failcheck: 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.
| Mistake | Symptom | Fix |
|---|---|---|
| Created an Application instead of an API in Auth0 Dashboard | Token validation fails; wrong audience | Create a new API (Resource Server) in Auth0 Dashboard → APIs |
| Audience doesn't match API identifier exactly | 401 Unauthorized — "Audience mismatch" | Copy the exact API Identifier string from Auth0 Dashboard → APIs |
ISSUER_BASE_URL missing the https:// scheme | Error: Invalid URL at startup | ISSUER_BASE_URL must be the full issuer URL: https://your-tenant.us.auth0.com |
Checking scope claim instead of permissions for RBAC | 403 always returned or permissions ignored | Use requiredScopes() for scope-based RBAC; use claimIncludes('permissions', 'read:data') for Auth0 RBAC permission claims |
| CORS not configured before auth middleware | Preflight OPTIONS requests return 401 | Add cors() middleware before auth() in the middleware chain |
.env file not loaded | undefined for domain/audience | Add import 'dotenv/config' at the top of the entry file |
Hardcoded domain/audience in source (incl. process.env.X || 'literal' fallbacks) | Secrets committed to source; fails security review | Put values in .env (ISSUER_BASE_URL / AUDIENCE) and let auth() read them automatically — no literal fallbacks |
req.auth is undefined | TypeError: Cannot read properties of undefined | Verify checkJwt middleware runs before the handler |
| Function | Description | Returns |
|---|---|---|
auth(options?) | JWT Bearer validation middleware | Handler — 401 if token invalid/missing |
requiredScopes(scopes) | Validates token has all required scopes | Handler — 403 if scopes missing |
scopeIncludesAny(scopes) | Validates token has at least one scope | Handler — 403 if no match |
claimEquals(claim, value) | Validates a claim equals a value | Handler — 401 if mismatch |
claimIncludes(claim, ...values) | Validates claim includes all values | Handler — 401 if incomplete |
claimCheck(fn, desc?) | Custom claim validation function | Handler — 401 if fn returns false |
| Option | Type | Description |
|---|---|---|
issuerBaseURL | string | Full issuer URL with https://. Optional — defaults to the ISSUER_BASE_URL env var |
audience | string | API Identifier from Auth0 Dashboard. Optional — defaults to the AUDIENCE env var |
tokenSigningAlg | string | Signing algorithm (default: RS256; use HS256 for symmetric) |
authRequired | boolean | Set false to make authentication optional (default: true) |
clockTolerance | number | Clock skew tolerance in seconds (no default; undefined unless set) |
dpop | DPoPOptions | DPoP configuration (see integration.md) |
| Variable | Description |
|---|---|
ISSUER_BASE_URL | Full issuer URL with https://, e.g. https://your-tenant.us.auth0.com (auto-detected by SDK) |
AUDIENCE | API Identifier, e.g. https://your-api-identifier (auto-detected by SDK) |
After successful validation, req.auth contains:
The node-oauth2-jwt-bearer monorepo contains three packages:
| Package | Purpose |
|---|---|
express-oauth2-jwt-bearer | Main package. Express middleware for JWT Bearer validation. Published to npm. |
access-token-jwt | Low-level JWT verification utilities (used internally). |
oauth2-bearer | RFC 6750 Bearer token extraction (used internally). |
In practice, you only install and import express-oauth2-jwt-bearer.
| Auth Pattern | SDK | When to Use |
|---|---|---|
| JWT Bearer (stateless) | express-oauth2-jwt-bearer | APIs called by SPAs, mobile apps, M2M clients |
| Session-based (stateful) | @auth0/express-openid-connect | Web apps with login UI and server-side sessions |