Using JWTs for API Authentication
Learn how to implement JWT-based API authentication with Bearer tokens, middleware validation, scope-based authorization, and error handling best practices.
Detailed Explanation
JWTs have become the dominant authentication mechanism for REST APIs, GraphQL APIs, and microservices. The Bearer token pattern provides a stateless, scalable way to authenticate and authorize API requests without server-side session storage.
The Bearer token pattern:
GET /api/users/me HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIn0.signature
The client includes the JWT in the Authorization header with the "Bearer" scheme (defined in RFC 6750). The API server extracts the token, validates it, and uses the embedded claims for authentication and authorization.
Server-side validation middleware:
A typical validation flow in middleware: (1) Extract the token from the Authorization header, (2) Decode the header to determine the algorithm, (3) Verify the signature using the appropriate key, (4) Check exp to ensure the token is not expired, (5) Verify iss matches the expected issuer, (6) Verify aud includes this API's identifier, (7) Extract user identity and claims for downstream use.
// Express.js middleware example
function authenticateJWT(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
const token = authHeader.split(' ')[1];
try {
const payload = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://auth.example.com',
audience: 'https://api.example.com'
});
req.user = payload;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
Scope-based authorization:
Beyond authentication (who is making the request), JWTs enable fine-grained authorization (what they can do). The scope claim lists the permissions granted to the token, such as read:users write:posts. API endpoints check whether the token's scope includes the required permission before processing the request.
Error responses:
Return 401 Unauthorized for missing or invalid tokens. Return 403 Forbidden when the token is valid but the user lacks the required scope or permissions. Include a WWW-Authenticate header with error details per RFC 6750. Never include internal error details (like "signature verification failed with key XYZ") in the response, as this leaks implementation details.
Use Case
A SaaS API validates JWT access tokens in middleware, extracting the tenant ID and user roles from claims to enforce multi-tenant data isolation on every request.