Middy JWT Authorization Middleware
raw JSON →middy-middleware-jwt-auth is a specialized middleware designed for the Middy.js framework, enabling JSON Web Token (JWT) authorization for AWS Lambda functions. Inspired by `express-jwt`, it simplifies the process of verifying JWTs and injecting the decoded payload into the Lambda `event.auth` object. The current stable version is `6.3.0`. The library follows the Middy.js release cadence, frequently updating to support new major versions of `@middy/core`. Key differentiators include its tight integration with the Middy ecosystem, robust type definitions for TypeScript users, and customizable token extraction and verification options, including support for various encryption algorithms and asynchronous secret retrieval. It aims to provide a reliable and easy-to-use solution for securing serverless API endpoints with JWTs.
Common errors
error TypeError: (0, middy_middleware_jwt_auth_1.JWTAuthMiddleware) is not a function ↓
import JWTAuthMiddleware from 'middy-middleware-jwt-auth'; error Error: 'jwt malformed' or 'invalid signature' ↓
Authorization header (typically Bearer <token>) is correctly formatted and that the secretOrPublicKey configured in the middleware matches the key used to sign the token. error Error: 'No authorization token was found' ↓
Authorization: Bearer <token> header, or if authentication is optional, set credentialsRequired: false in the middleware configuration. error TypeError: event.auth is undefined ↓
event.auth before accessing its properties: if (event.auth && event.auth.payload) { ... }. Alternatively, ensure credentialsRequired: true if the auth object is strictly needed. Warnings
breaking Version 6.0.0 introduced a breaking change by upgrading its underlying `jsonwebtoken` dependency to version 9. Users must review the migration notes for `jsonwebtoken` v9, as related breaking changes (e.g., in options for `sign` or `verify` methods) now apply to `middy-middleware-jwt-auth`. ↓
gotcha The `JWTAuthMiddleware` is a default export. Attempting to import it as a named export (e.g., `import { JWTAuthMiddleware } from '...'`) will lead to runtime errors like `TypeError: (0, middy_middleware_jwt_auth_1.JWTAuthMiddleware) is not a function` in CommonJS contexts or `undefined` in ESM. ↓
gotcha The middleware's `credentialsRequired` option defaults to `false`. This means if no `Authorization` header is present or the token is invalid, the middleware will proceed without throwing an error, but `event.auth` will be `undefined`. You must explicitly set it to `true` to enforce authentication for a given handler. ↓
gotcha Since version 6.3.0, `secretOrPublicKey` and `tokenSource` can be asynchronous functions. While this offers flexibility (e.g., fetching secrets from Secrets Manager), ensure your implementation correctly handles promises and callbacks, as incorrect usage might lead to verification failures or unexpected delays. ↓
Install
npm install middy-middleware-jwt-auth yarn add middy-middleware-jwt-auth pnpm add middy-middleware-jwt-auth Imports
- JWTAuthMiddleware wrong
import { JWTAuthMiddleware } from 'middy-middleware-jwt-auth';correctimport JWTAuthMiddleware from 'middy-middleware-jwt-auth'; - EncryptionAlgorithms wrong
import EncryptionAlgorithms from 'middy-middleware-jwt-auth';correctimport { EncryptionAlgorithms } from 'middy-middleware-jwt-auth'; - IAuthorizedEvent wrong
import IAuthorizedEvent from 'middy-middleware-jwt-auth';correctimport { IAuthorizedEvent } from 'middy-middleware-jwt-auth';
Quickstart
import createHttpError from "http-errors";
import middy from "@middy/core";
import httpErrorHandler from "@middy/http-error-handler";
import httpHeaderNormalizer from "@middy/http-header-normalizer";
import JWTAuthMiddleware, {
EncryptionAlgorithms,
IAuthorizedEvent,
} from "middy-middleware-jwt-auth";
// Define the token payload structure expected from your JWT
interface ITokenPayload {
permissions: string[];
}
// Type guard for the token payload to ensure runtime safety
function isTokenPayload(token: any): token is ITokenPayload {
return (
token != null &&
Array.isArray(token.permissions) &&
token.permissions.every((permission: any) => typeof permission === "string")
);
}
// Your AWS Lambda handler function
const helloWorld = async (event: IAuthorizedEvent<ITokenPayload>) => {
// Access the authenticated payload from event.auth
if (!event.auth || !isTokenPayload(event.auth.payload)) {
throw createHttpError(401, "Unauthorized: Invalid token payload");
}
// Perform authorization check based on permissions in the token
if (event.auth.payload.permissions.indexOf("helloWorld") === -1) {
throw createHttpError(
403,
`User not authorized for helloWorld, only found permissions [${event.auth.payload.permissions.join(", ")}]`,
{
type: "NotAuthorized",
},
);
}
return {
body: JSON.stringify({
data: `Hello world! Here's your token: ${event.auth.token}`,
userId: event.auth.payload.sub // Assuming 'sub' is in your token
}),
statusCode: 200,
};
};
// 'Middyfy' your handler and attach the JWT authorization middleware
export const handler = middy(helloWorld)
.use(httpHeaderNormalizer()) // Ensures Authorization header is consistently cased
.use(httpErrorHandler()) // Catches errors thrown by JWTAuthMiddleware and returns appropriate HTTP responses
.use(
JWTAuthMiddleware({
algorithm: EncryptionAlgorithms.HS256,
credentialsRequired: true, // Set to true to make a missing or invalid token result in a 401
secretOrPublicKey: process.env.JWT_SECRET ?? 'supersecretkey',
// You can also specify an async function for secretOrPublicKey or tokenSource since v6.3.0
// secretOrPublicKey: async (header, payload, done) => { /* fetch secret */ done(null, 'secret'); },
// tokenSource: (event) => event.headers['x-custom-token'],
}),
);