{"id":18348,"library":"express-oauth2-jwt-bearer","title":"Express OAuth2 JWT Bearer","description":"Authentication middleware for Express.js that validates JWT Bearer access tokens issued by an OAuth 2.0 authorization server. Version 1.8.0 supports DPoP (Proof-of-Possession) authentication, multiple custom domains, clock tolerance for nbf claim, and Node.js versions 12 through 24. Maintained by Auth0 with 100% test coverage. Differentiates from other JWT middleware by being Auth0-optimized, supporting OAuth 2.0 token validation (not just JWT decoding), and providing built-in security headers guidance.","status":"active","version":"1.8.0","language":"javascript","source_language":"en","source_url":"https://github.com/auth0/node-oauth2-jwt-bearer","tags":["javascript","typescript"],"install":[{"cmd":"npm install express-oauth2-jwt-bearer","lang":"bash","label":"npm"},{"cmd":"yarn add express-oauth2-jwt-bearer","lang":"bash","label":"yarn"},{"cmd":"pnpm add express-oauth2-jwt-bearer","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for Express.js middleware integration","package":"express","optional":false},{"reason":"Retrieves RSA public keys from JWKS endpoint for token signature verification","package":"jwks-rsa","optional":false},{"reason":"Used for JWT decoding and verification under the hood","package":"jsonwebtoken","optional":false}],"imports":[{"note":"ESM is fully supported. In CommonJS, use const { auth } = require('express-oauth2-jwt-bearer').","wrong":"const auth = require('express-oauth2-jwt-bearer')","symbol":"auth","correct":"import { auth } from 'express-oauth2-jwt-bearer'"},{"note":"The error type is VerificationError, not UnauthorizedError. Use err.status and err.headers for RFC 6750 compliance.","wrong":"import { UnauthorizedError } from 'express-oauth2-jwt-bearer'","symbol":"VerificationError","correct":"import { VerificationError } from 'express-oauth2-jwt-bearer'"},{"note":"Thrown when custom claim checks fail. Always use err.status to determine HTTP response code.","wrong":"import { CheckError } from 'express-oauth2-jwt-bearer'","symbol":"ClaimCheckError","correct":"import { ClaimCheckError } from 'express-oauth2-jwt-bearer'"}],"quickstart":{"code":"import { auth, requiredScopes } from 'express-oauth2-jwt-bearer';\nimport express from 'express';\n\nconst app = express();\n\n// Validate JWT bearer token\napp.use(\n  auth({\n    issuerBaseURL: process.env.ISSUER_BASE_URL ?? 'https://example.auth0.com',\n    audience: process.env.AUDIENCE ?? 'https://api.example.com',\n  })\n);\n\n// Protected route\napp.get('/api/messages', requiredScopes('read:messages'), (req, res) => {\n  res.json({\n    message: 'Access granted',\n    payload: req.auth.payload,\n  });\n});\n\n// Error handling (Express default handles err.status and err.headers)\nconst port = process.env.PORT ?? 3000;\napp.listen(port, () => console.log(`Server running on port ${port}`));","lang":"typescript","description":"Shows how to configure auth middleware, protect a route with scopes, and access the decoded token payload."},"warnings":[{"fix":"Update to v1.7.3 or later. If you relied on the previous 401 status, adjust your error handling logic.","message":"In v1.7.3, the unauthorized response status code changed from 401 to 403 for insufficient scope errors, as per RFC 6750.","severity":"breaking","affected_versions":">=1.7.0 <1.7.3"},{"fix":"In error handling middleware, use err.status (e.g., if (err.status === 403) {...}) instead of assuming 401.","message":"The library silently changes 401 to 403 in some error conditions; always use err.status from the error object, not a hardcoded value.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use issuerBaseURL with a JWKS endpoint instead of secret. If you must use HS256, ensure secret is a strong symmetric key.","message":"The 'secret' option (for symmetric algorithms like HS256) is deprecated since v1.4.0 and discouraged for production; use asymmetric keys (RS256) via issuerBaseURL.","severity":"deprecated","affected_versions":">=1.4.0"},{"fix":"Specify tokenSigningAlg: 'HS256' when using symmetric secret. Example: auth({ issuer: '...', audience: '...', secret: '...', tokenSigningAlg: 'HS256' })","message":"When using issuer (not issuerBaseURL) for symmetric algorithms, you must also specify tokenSigningAlg: 'HS256'. Omitting it defaults to RS256 which will fail.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Read EXAMPLES.md for full DPoP config options. Set dpop: { enforce: true } to require DPoP proof.","message":"DPoP authentication is in early access; the default mode accepts both DPoP and Bearer tokens. To enforce DPoP-only, you must set dpop: { enforce: true }.","severity":"gotcha","affected_versions":">=1.7.0"}],"env_vars":null,"last_verified":"2026-04-25T00:00:00.000Z","next_check":"2026-07-24T00:00:00.000Z","problems":[{"fix":"Add issuerBaseURL to auth(): auth({ issuerBaseURL: 'https://your-tenant.auth0.com/', audience: '...' })","cause":"Missing issuerBaseURL or issuer option in auth() config.","error":"express-oauth2-jwt-bearer: UnauthorizedError: jwt issuer is not configured"},{"fix":"Use named import: import { auth } from 'express-oauth2-jwt-bearer' (or const { auth } = require(...) for CJS)","cause":"Incorrect import: using default import instead of named import.","error":"TypeError: Cannot destructure property 'auth' of (intermediate value) as it is undefined"},{"fix":"Set NODE_TLS_REJECT_UNAUTHORIZED=0 (only for development) or configure proper CA certificates.","cause":"HTTPS TLS certificate validation failed, often due to self-signed certs or corporate proxies.","error":"jwks-rsa: Error: unable to get local issuer certificate"}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}