ExpressJS middleware for validating Azure AD JWT tokens on all routes

ExpressJS has an middleware building pattern which is suitable for building functions that pre-define conditions, and or manipulate request/response objects. This pattern is evaluated before processing continues to the business logic on route level.

This pattern is extremely well suited for scenarios where you want the function to cover large part of the application without adding separate logic for each route. Such scenarios might be authorization and logging for example.

Reason I built this middleware was to understand how to use Azure AD App registrations and JSONWebToken libraries with ExpressJS in a minimal way which achieves the main purpose of the authorization logic.

Existing solutions recommended for production include incorporating well known NPM modules such PassPortJS (https://github.com/jaredhanson/passport) and/or JWKS-RSA+JSONWebToken. This project uses JSONWebToken and replaces JWKS-RSA metadata call with simple request to Azure AD metadata endpoint. The InternalClient code in the project is redundant (50%), but it’s there to get somebody testing this library quickly forward.

Pre-requirements

Options

Example options (Dont use the same values for TenantID and ClientID)

const tenantId = "f996ef8a-f93b-47e5-9ed9-a9d5e5b95245"
const options = {
    audience:"https://jwtapi.dewi.red",
    issuer:"https://sts.windows.net/"+tenantId +"/",
    AllowInternalAPIClient:true,
        clientOptions: {
        ClientId:"cb505207-7698-49e1-8791-40b6eadac75d",
        RedirectUri:"http://localhost:3000/token"
        }
}

How to test

0. Git Clone

3. Register app ‘NodeClient’

Possibly wrong client type: Check that the Client has redirect uri set to public - AzureAD Error:AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.

4. Add API delegate permissions to the Node Client for the NodeAPI with the selection ‘Add a permission’

5. Complete the config with the following params

Example based on this guide

const tenantId = "f996ef8a-f93b-47e5-9ed9-a9d5e5b95245"
const options = {
    audience:"https://jwtapi.dewi.red",
    issuer:"https://sts.windows.net/"+tenantId +"/",
    AllowInternalAPIClient:true,
        clientOptions: {
        ClientId:"355e0149-c459-411e-a0b2-6e6f8cee286f",
        RedirectUri:"http://localhost:3000/token"
        }
}

5. Install dependencies and run the example

6. Use Any Public Client to get token, or the built-in client

For testing login you can use /aad path (browse http://localhost:3000/token from your browser, this will bring up an consent dialog to the application, unless you did admin grant earlier)

Recommended mode is to set the AllowAPIClient:false and use your own client implementation