Skip to main content

Protect your API on Node (Express)

note

Extract the Bearer Token from request headerโ€‹

A authorized request should contain an Authorization header with Bearer <access_token> as its content. Extract the Authorization Token from the request header:

// auth_middleware.ts

import { IncomingHttpHeaders } from 'http';

const extractBearerTokenFromHeaders = ({ authorization }: IncomingHttpHeaders) => {
const bearerTokenIdentifier = 'Bearer';

if (!authorization) {
throw new Error({ code: 'auth.authorization_header_missing', status: 401 });
}

if (!authorization.startsWith(bearerTokenIdentifier)) {
throw new Error({ code: 'auth.authorization_token_type_not_supported', status: 401 });
}

return authorization.slice(bearerTokenIdentifier.length + 1);
};

Token validationโ€‹

For demonstration, we use jose package to validate the token's signature, expiration status, and required claims.

Install jose as your dependencyโ€‹

npm i jose --save

Retrieve Logto's OIDC configurationsโ€‹

You will need a JWK public key set and the token issuer to verify the signature and source of the received JWS token. All the latest public Logto Authorization Configurations can be found at https://<your-logto-domain>/oidc/.well-known/openid-configuration.

e.g. Call https://logto.dev/oidc/.well-known/openid-configuration. And locate the following two fields in the response body:

{
"jwks_uri": "https://logto.dev/oidc/jwks",
"issuer": "https://logto.dev/oidc"
}

Add auth middlewareโ€‹

Jose's jwtVerify method may helps you to verify the token's JWS format, token signature, issuer, audience and the expiration status. A exception will be thrown if validation failed.

note

For ๐Ÿ” RBAC, scope validation is also required.

// auth-middleware.ts

import { createRemoteJWKSet, jwtVerify } from 'jose';

//...

export const verifyAuthFromRequest = async (req, res, next) => {
// Extract the token
const token = extractBearerTokenFromHeaders(req.headers);

const { payload } = await jwtVerify(
token, // The raw Bearer Token extracted from the request header
createRemoteJWKSet(new URL('https://<your-logto-domain>/oidc/jwks')), // generate a jwks using jwks_uri inquired from Logto server
{
// expected issuer of the token, should be issued by the Logto server
issuer: 'https://<your-logto-domain>/oidc',
// expected audience token, should be the resource indicator of the current API
audience: '<your request listener resource indicator>',
}
);

// if you are using RBAC
assert(payload.scope.includes('some_scope'));

// custom payload logic
userId = payload.sub;

return next();
};

Apply middleware to your APIโ€‹

import { verifyAuthFromRequest } from '/middleware/auth-middleware.ts';

app.get('/user/:id', verifyAuthFromRequest, (req, res, next) => {
// Custom code
});