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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@makerx/express-bearer

v1.2.0

Published

Bearer token validation middleware for Express.js

Downloads

384

Readme

Express bearer

An express middleware to decode and verify JWTs from bearer authorization headers.

What does this do?

  • loads signing keys from a JWKS endpoint using jwks-rsa
  • verifies and decodes a JWT from a Bearer authorization header using jsonwebtoken
  • sets req.user to the verified decoded JWT payload (claims)

Usage

import { bearerTokenMiddleware, BearerConfig } from '@makerxstudio/express-bearer'

const app = express()
const config: BearerConfig = {
  jwksUri: 'https://login.microsoftonline.com/<tenant ID>/discovery/v2.0/keys',
  verifyOptions: {
    issuer: 'https://login.microsoftonline.com/<tenant ID>/v2.0',
    audience: '<audience ID>',
  },
}

// add the bearer token middleware (to all routes)
app.use(bearerTokenMiddleware({ config }))
// or... add to a specific route
app.post('/api/admin/*', bearerTokenMiddleware({ config }))
// or... add to a specific route + make authentication mandatory
app.post('/api/admin/*', bearerTokenMiddleware({ config, tokenIsRequired: true }))

// access the user, check the roles claim
app.post('/api/admin/*', (req, res, next) => {
  const roles = (req.user?.roles as string[]) ?? []
  if (!roles.includes('Admin')) throw new Error('Authorization failed')
  next()
})

The middleware will:

  • Return 401 Unauthorized when the JWT fails decoding / verification
  • Return 401 Unauthorized if there is no Bearer {token} authorization header and tokenIsRequired is set to true (default is false)

Options

BearerAuthOptions:

| Option | Description | | ----------------- | ------------------------------------------------------------------------------------------------------- | | config | The JWT handling config *BearerConfig (or *BearerConfigCallback for per-host config). | | tokenIsRequired | Controls whether requests with no Bearer {token} authorization header are rejected, default: false. | | logger | Optional logger implementation to log token validation errors, handler setup info entry etc. |

JWT handling config:

| Option | Description | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | jwksUri | The endpoint to load signing keys via jwks-rsa | | verifyOptions | The options passed into jwt.verify | | unauthorizedResponse | Optional. Callback of type (req: Request, res: Response) => Response) which provides a way to customise the HTTP response when the bearer token is required and not present, or the validation fails.If not provided, a plain text 401 Unauthorized response is returned. | | explicitNoIssuerValidation | Optional. The default behaviour is to enforce issuer validation through verifyOptions.issuer to avoid security issues through misconfiguration.If it's intentional to not validate the issuer of incoming tokens, set this property to true. | | explicitNoAudienceValidation | Optional. The default behaviour is to enforce audience validation through verifyOptions.audience to avoid security issues through misconfiguration.If it's intentional to not validate the audience of incoming tokens, set this property to true. |

Multitenant apps

To specify per-host config, provide a *BearerConfigCallback in the form of (host: string) => BearerConfig.

Note: the callback will only be called once per host (config is cached).

Apps accepting bearer tokens from multiple issuers

If your app needs to accept bearer tokens from multiple issuers (OIDC endpoints) each with different JWKS URIs on a single endpoint (not varied by host), multiIssuerBearerTokenMiddleware supports this with a different approach. It will:

  • decode the token without verifying it
  • use the iss claim to access the issuer-specific config IssuerOptions (or return unauthorized, if not found)
  • verify the token using the issuer-specific config (caching JwksClient instances per JWKS URI)

Multi-issuer options

import { IssuerOptions, multiIssuerBearerTokenMiddleware, MultiIssuerBearerAuthOptions } from '@makerxstudio/express-bearer'

const app = express()
const issuerOptions: Record<string, IssuerOptions> = {
  'https://example.com/oidc': {
    jwksUri: 'https://example.com/oidc/jwks',
    verifyOptions: {
      audience: 'https://api.example.com',
    },
  },
  'https://login.microsoftonline.com/<tenant ID>/v2.0': {
    jwksUri: 'https://login.microsoftonline.com/<tenant ID>/discovery/v2.0/keys',
    verifyOptions: {
      audience: '<audience ID>',
    },
  },
}

// add the multi issuer bearer token middleware (to all routes)
app.use(multiIssuerBearerTokenMiddleware({ issuerOptions, tokenIsRequired: true }))

Logging

Set the logger implementation to an object that fulfills the Logger definition:

type Logger = {
  error(message: string, ...optionalParams: unknown[]): void
  warn(message: string, ...optionalParams: unknown[]): void
  info(message: string, ...optionalParams: unknown[]): void
  verbose(message: string, ...optionalParams: unknown[]): void
  debug(message: string, ...optionalParams: unknown[]): void
}

Note: this type is compatible with winston loggers.

The following example uses console logging:

const logger: Logger = {
  error: (message: string, ...params: unknown[]) => console.error(message, ...params),
  warn: (message: string, ...params: unknown[]) => console.warn(message, ...params),
  info: (message: string, ...params: unknown[]) => console.info(message, ...params),
  verbose: (message: string, ...params: unknown[]) => console.trace(message, ...params),
  debug: (message: string, ...params: unknown[]) => console.debug(message, ...params),
}

const config: BearerConfig = {
  jwksUri: ...,
  verifyOptions: { ... },
  logger,
}