Skip to main content
A new Beta version of this quickstart is available using the @auth0/auth0-express-api SDK, which will soon replace this guide. Try the Beta quickstart →

Use AI to integrate Auth0

If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 API authentication automatically in minutes using agent skills.Install:
Then ask your AI assistant:
Your AI assistant will automatically create your Auth0 API, fetch credentials, install express-oauth2-jwt-bearer, configure the JWT middleware, and protect your API endpoints with token validation. Full agent skills documentation →
Prerequisites: Before you begin, ensure you have the following installed:
  • Node.js 18 LTS or newer (supports ^18.12.0 || ^20.2.0 || ^22.1.0 || ^24.0.0)
  • npm 8+ or yarn 1.22+ or pnpm 8+
Verify installation: node --version && npm --versionExpress Version Compatibility: This quickstart works with Express 4.x and Express 5.x.

Get Started

This quickstart demonstrates how to protect Express.js API endpoints using JWT access tokens. You’ll build a secure API that validates Auth0 access tokens, protects routes, and implements scope-based authorization.
1

Create a new project

Create a new directory for your Express API and initialize a Node.js project.
Initialize the project
Create the project structure
2

Install the express-oauth2-jwt-bearer SDK

Install the required dependencies
Add start scripts to your package.json:
package.json
3

Setup your Auth0 API

Next, you need to create a new API on your Auth0 tenant and add the environment variables to your project.You have two options to set up your Auth0 API: use a CLI command or configure manually via the Dashboard:
Run the following command in your project’s root directory to create an Auth0 API:
This command will:
  1. Check if you’re authenticated (and prompt for login if needed)
  2. Create an Auth0 API with the specified identifier
  3. Display the API details including the domain and identifier
After creation, copy the Identifier and your Domain values, then create your .env file:
.env
Replace YOUR_AUTH0_DOMAIN with your Auth0 tenant domain (e.g., dev-abc123.us.auth0.com) and YOUR_API_IDENTIFIER with your API identifier (e.g., https://my-express-api.example.com).
Verify your .env file exists: cat .env (Mac/Linux) or type .env (Windows)
4

Configure the JWT middleware

Create your Express server and configure JWT validation:
server.js
What this does:
  • Creates JWT validation middleware using your Auth0 domain and API audience
  • Validates the iss and aud claims on incoming access tokens
  • Makes checkJwt available for protecting individual routes
5

Create API routes

Add public and protected routes to your server.js:
server.js
Key points:
  • Public routes don’t require authentication
  • Protected routes use the checkJwt middleware to require a valid JWT
  • Scoped routes use requiredScopes() to require specific permissions in the token
  • req.auth.payload contains the decoded JWT claims for authenticated requests
  • The sub claim contains the user’s unique identifier
6

Run your API

Start the development server:
Your API is now running at http://localhost:3001.
The --watch flag in Node.js 18+ automatically restarts the server when files change.
7

Test your API

Test the public endpoint (no authentication required):
You should see:
Test the protected endpoint without a token (should fail):
You should see a 401 Unauthorized error:
To test with a valid token:
  1. Go to Auth0 DashboardApplicationsAPIs
  2. Select your API → Test tab
  3. Copy the generated access token
Test your protected endpoint:
You should see:
CheckpointYou should now have a protected API. Your API:
  1. Accepts requests to public endpoints without authentication
  2. Rejects requests to protected endpoints without a valid token
  3. Validates JWT tokens against your Auth0 domain and audience
  4. Provides user information from the token claims via req.auth.payload

Advanced Usage

Scopes allow fine-grained access control. You can require specific scopes for different endpoints.Configure scopes in Auth0:
  1. In the Auth0 Dashboard, go to ApplicationsAPIs → Your API
  2. Navigate to the Permissions tab
  3. Add permissions like read:messages, write:messages, admin:access
Protect routes with scopes:
server.js
If a request lacks the required scope, the API returns 403 Forbidden with an insufficient_scope error. Ensure the client application requests the correct scopes when obtaining an access token.
Beyond scopes, you can validate custom claims in the JWT payload:
server.js
Custom claims must use namespaced URLs (e.g., https://myapp.com/roles) unless they’re standard OIDC claims. Learn more about custom claims.
Allow both authenticated and anonymous access to the same route:
server.js
Enable CORS to allow requests from web applications:
server.js
For production, specify exact origins:
server.js
Add comprehensive error handling for authentication errors:
server.js
For TypeScript projects, install type definitions and configure your project:
Create server.ts:
server.ts
Add a tsconfig.json:
tsconfig.json
Run with: npx ts-node server.ts

Troubleshooting

”No authorization token was found”

Problem: The API cannot find the access token in the request.Solutions:
  1. Ensure the Authorization header is present: Authorization: Bearer YOUR_TOKEN
  2. Check that “Bearer” is included before the token
  3. Verify the token is not expired

”Invalid token” or “jwt malformed”

Problem: The token format is invalid.Solutions:
  1. Ensure you’re using an access token, not an ID token
  2. The token should be obtained with your API’s audience parameter
  3. Check that the token is a valid JWT (should have three parts separated by dots)

Unexpected “iss” or “aud” value

Problem: The issuer or audience in the token doesn’t match your configuration.Solutions:
  1. Decode your token at jwt.io
  2. Check the iss claim matches https://YOUR_AUTH0_DOMAIN/ (note the trailing slash)
  3. Check the aud claim matches your AUTH0_AUDIENCE exactly
  4. Verify your .env values:

“You must provide an issuerBaseURL” or “audience is required”

Problem: Environment variables are not being loaded.Solutions:
  1. Ensure .env file exists in your project root
  2. Verify dotenv is installed: npm install dotenv
  3. Add require('dotenv').config() at the very top of your server file
  4. Check variable names match exactly (case-sensitive)

401 Unauthorized on all requests

Possible causes:
  • Token is expired
  • Audience doesn’t match
  • Issuer doesn’t match
Debug steps:
  1. Decode your token at jwt.io
  2. Check the exp claim hasn’t passed
  3. Verify aud claim matches your AUTH0_AUDIENCE exactly
  4. Verify iss claim is https://{AUTH0_DOMAIN}/
  5. Ensure Authorization header format is Bearer YOUR_TOKEN (with space)

403 Forbidden with “insufficient_scope”

Problem: The token doesn’t have the required scopes.Solutions:
  1. Verify the scopes are defined in your Auth0 API (Dashboard → ApplicationsAPIsPermissions)
  2. Request the scopes when obtaining the token
  3. Check the token’s scope claim includes the required scopes

CORS errors in browser

Problem: Browser blocks API requests due to CORS policy.Solution: Install and configure cors:

Next Steps

Now that you have a protected API, consider exploring:

Resources