https://github.com/makerxstudio/express-bearer
An express middleware to decode and verify JWTs from bearer authorization headers.
https://github.com/makerxstudio/express-bearer
auth express express-bearer npm package typescript
Last synced: about 1 year ago
JSON representation
An express middleware to decode and verify JWTs from bearer authorization headers.
- Host: GitHub
- URL: https://github.com/makerxstudio/express-bearer
- Owner: MakerXStudio
- License: mit
- Created: 2022-08-31T06:08:58.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2024-12-23T00:57:57.000Z (over 1 year ago)
- Last Synced: 2025-03-29T08:11:20.175Z (about 1 year ago)
- Topics: auth, express, express-bearer, npm, package, typescript
- Language: TypeScript
- Homepage:
- Size: 594 KB
- Stars: 0
- Watchers: 13
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
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](https://github.com/auth0/node-jwks-rsa#readme)
- verifies and decodes a JWT from a Bearer authorization header using [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback)
- sets `req.user` to the verified decoded JWT payload (claims)
## Usage
```ts
import { bearerTokenMiddleware, BearerConfig } from '@makerxstudio/express-bearer'
const app = express()
const config: BearerConfig = {
jwksUri: 'https://login.microsoftonline.com//discovery/v2.0/keys',
verifyOptions: {
issuer: 'https://login.microsoftonline.com//v2.0',
audience: '',
},
}
// 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](https://github.com/auth0/node-jwks-rsa#readme) |
| `verifyOptions` | The options passed into [jwt.verify](https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback) |
| `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
```ts
import { IssuerOptions, multiIssuerBearerTokenMiddleware, MultiIssuerBearerAuthOptions } from '@makerxstudio/express-bearer'
const app = express()
const issuerOptions: Record = {
'https://example.com/oidc': {
jwksUri: 'https://example.com/oidc/jwks',
verifyOptions: {
audience: 'https://api.example.com',
},
},
'https://login.microsoftonline.com//v2.0': {
jwksUri: 'https://login.microsoftonline.com//discovery/v2.0/keys',
verifyOptions: {
audience: '',
},
},
}
// 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:
```ts
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](https://github.com/winstonjs/winston).
The following example uses console logging:
```ts
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,
}
```