npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mfbtech/express-msal-token

v1.0.0

Published

Express middleware to validate MSAL tokens

Readme

express-msal-token

Express middleware to validate signature, issuer, and audience of MSAL tokens

WARNING: This app is something of a WIP. It relies on expressjwt and jwks-rsa for the underlying validation. Those are well tested, popular libraries, so it should be fine from that perspective. However, there is a fair bit of nuance to how MSAL generates tokens and I'm not sure this captures all the various use cases (e.g., multitenant, B2C, etc). Feel free to raise issues with suggestions for improvement.

Quickstart

const expressMsalToken = await buildExpressMsalToken({
  tenantIdOrDomain: "contoso.com",
  audience: audienceUtils.v2Audience({ apiClientId: "0000-ABCDE-12345-0000" }),
  tokenVersion: 2
})

app.get("/authorized", expressMsalToken, (req: WithMsalAuth<Request>, res) => {
  res.status(200).send(`Welcome ${req.auth?.name ?? "unknown"}`)
})

Usage

buildExpressMsalToken

async function buildExpressMsalToken(args: {
  tenantIdOrDomain: string
  audience: Audience
  tokenVersion: 1 | 2
}): Promise<MiddlewareWithRequest<RequestLike>>

This function builds the middleware to decrypt an msal token and validate the issuer and audience. It takes the following parameters:

tenantIdOrDomain: Either the tenant id of an Azure tenant or the domain of the tenant.

audience: The audience value to validate against the aud claim in the token. Use the audienceUtils tools to generate this as it is a nominally typed value.

tokenVersion Either 1 or 2. These are the two version of tokens MSAL will issue. Note that if you setup a registration via the Azure GUI it currently will default to v1.

audienceUtils

A collection of utilities to generate the audience value. The audience value is different depending on whether you are using a v1 or v2 token, as explained here.

In v1 access tokens the aud claim is set by default to a URL in the format api://[client id of the app registration] -- which is what this function generates. But it can actually be set to any URI so there is no way to set it deterministically short of just checking the API scope settings in the app registration

audienceUtils.v1DefaultAudience will generate the audience from the apiClientId which is usually what you want for v1 tokens, but not guaranteed.

audienceUtils.v1Audience lets you generate an arbitrary audience if you aren't using the default

audienceUtils.v2Audience generates the audience from the apiClientId (they are actually the same values--it just gives it a nominal type)

In v2 access tokens the aud claim is always the client id of the application registration for the api app.

Types

Inside this package we use express types from 4.17.20 to ensure compatibility with the types included by jwks-rsa -- which have not been upgraded to 5.0.0.

The middleware should still work with both versions of express -- v4 and v5 -- since the type differences are irrelevant to this middleware.

In order to get correct typing on your req object after the middleware runs we export a utility type called WithMsalAuth<T>. Call it with the Request type from the version of express you are running and it will add the auth property to that type with the various claims added by MSAL.

For example:

import type { Request } from "express"

// setup app, middelware etc

app.get("/", msalTokenMiddleware, (req: WithMsalAuth<Request>, res) => {
  //endpoint logic
})

Note, we don't type every possible claim value as these can differ based on variety of things, including v1 vs v2 tokens, optional claims set, MS Graph permissions etc. Commonly used ones are included.

{
  /** Display name */
  name?: string
  /** Unique id of the user */
  oid?: string
  /** Allowed scope on the resource/API */
  scp?: string
  /** Application roles assigned to user */
  roles?: string[]
  /** Unique id for the user in the context of the application (not globally) */
  sub?: string
  /** Tenant id */
  tid?: string
  /** Version of the access token */
  ver?: string
}

References

https://learn.microsoft.com/en-us/entra/identity-platform/access-tokens

https://learn.microsoft.com/en-us/entra/identity-platform/access-token-claims-reference

https://github.com/AzureAD/microsoft-identity-web/discussions/2405

https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/6113