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- and claim-based authorization.Create a new project
package.json to use ES modules and add start scripts:Setup your Auth0 API
- CLI
- Dashboard
.env file:Replace YOUR_API_IDENTIFIER with the identifier you used above (e.g., https://my-express-api.example.com).Configure the JWT middleware
createAuth0Api() on your Express application to configure JWT validation. Then add public and protected routes.createAuth0Api()readsAUTH0_DOMAINandAUTH0_AUDIENCEfrom environment variables automaticallyrequiresAuth()validates theAuthorization: Bearer <token>header on each requestreq.auth0.usercontains the decoded JWT claims for authenticated requests —subis the user’s unique identifier
Protect a route with a required scope
scopes option to requiresAuth() — the SDK returns 403 insufficient_scope if the token is missing the scope.scopesInclude, claimEquals, claimIncludes, and claimCheck — covered in Advanced Usage.Run your API
Test your API
- Go to Auth0 Dashboard → Applications > APIs
- Select your API → Test tab
- Copy the generated access token
- Accepts requests to public endpoints without a token
- Returns the protected response when a valid access token is provided
- Validates JWTs against your Auth0 domain and audience
- Exposes decoded token claims via
req.auth0.user
Advanced Usage
Matching multiple scopes with scopesInclude
Matching multiple scopes with scopesInclude
scopesInclude when a route should accept any one of several scopes, or require several at once. By default it matches any of the listed scopes; pass { match: 'all' } to require all of them. Scopes can be passed as an array or a space-separated string — these examples use arrays.Defining custom token claims with TypeScript
Defining custom token claims with TypeScript
Token interface to get type-safe access to custom claims:CORS configuration for web clients
CORS configuration for web clients
Configuring scopes in the Auth0 Dashboard
Configuring scopes in the Auth0 Dashboard
- Go to Auth0 Dashboard → Applications > APIs → your API
- Navigate to the Permissions tab
- Add permissions like
read:messages,write:messages,read:admin - Click Save
403 Forbidden.Troubleshooting
401 with an empty body and a bare 'WWW-Authenticate: Bearer' header
401 with an empty body and a bare 'WWW-Authenticate: Bearer' header
Authorization header is missing or malformed, so no bearer token could be extracted. Per RFC 6750, the SDK returns 401 with a bare WWW-Authenticate: Bearer header and no error body in this case. This is distinct from a token that is present but invalid or expired, which returns 401 with an invalid_token error and a JSON body (see below).Fix:- Ensure the header is present:
Authorization: Bearer YOUR_TOKEN - Verify “Bearer” (with a capital B and a space) precedes the token
'Invalid token' or audience/issuer mismatch (401)
'Invalid token' or audience/issuer mismatch (401)
- Decode your token at jwt.io
- Check
issmatcheshttps://{yourDomain}/(note the trailing slash) - Check
audmatches yourAUTH0_AUDIENCEexactly - Make sure you’re using an access token, not an ID token — access tokens are obtained with the
audienceparameter
'Insufficient scope' (403)
'Insufficient scope' (403)
- Verify the scope is defined in your API’s Permissions tab in the Auth0 Dashboard
- Ensure the client is requesting the scope when obtaining the access token
- Decode the token at jwt.io and check the
scopeclaim
Environment variables not loaded
Environment variables not loaded
dotenv is not configured, or variable names are wrong.Fix:- Ensure
import 'dotenv/config'is the first import in your entry file - Verify
.envcontainsAUTH0_DOMAINandAUTH0_AUDIENCE - Debug:
ESM import errors ('Cannot use import statement')
ESM import errors ('Cannot use import statement')
@auth0/auth0-express-api SDK uses ES modules.Fix: Add "type": "module" to your package.json:📁 package.jsonserver.mjs.Next Steps
- Add Login to an Express Web App — Use
@auth0/auth0-expressfor session-based auth in web apps - Role-Based Access Control — Implement fine-grained permissions
- Access Token Best Practices — Learn about access token handling
- Monitor Your API — Set up logging and monitoring
Resources
- auth0/auth0-express-api GitHub — Source code and examples
- Auth0 Community — Get help from the community
- JWT.io — Debug and decode JWTs