https://github.com/digicatapult/tsoa-oauth-express
Authentication handler for TSOA using OAuth2 JWT tokens
https://github.com/digicatapult/tsoa-oauth-express
authentication express oauth2 tsoa
Last synced: 3 months ago
JSON representation
Authentication handler for TSOA using OAuth2 JWT tokens
- Host: GitHub
- URL: https://github.com/digicatapult/tsoa-oauth-express
- Owner: digicatapult
- License: apache-2.0
- Created: 2024-05-13T15:10:47.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2026-03-26T17:34:36.000Z (3 months ago)
- Last Synced: 2026-03-26T22:51:02.022Z (3 months ago)
- Topics: authentication, express, oauth2, tsoa
- Language: TypeScript
- Homepage:
- Size: 761 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# tsoa-oauth-express
This library enables easy implementation of OAuth2 authentication for [tsoa](https://tsoa-community.github.io/docs/) on [express](http://expressjs.com/). To use this library first add it as an `npm` dependency to your existing `tsoa` application.
```sh
npm i @digicatapult/tsoa-oauth-express
```
Your authentication file (see tsoa's documentation on authentication setup [here](https://tsoa-community.github.io/docs/authentication.html)) will then need to contain something like:
```ts
import type express from 'express'
import type * as jwt from 'jsonwebtoken'
import mkExpressAuthentication, { AuthOptions } from '@digicatapult/tsoa-oauth-express'
// module options
const options: AuthOptions = {
...
}
export const expressAuthentication = mkExpressAuthentication(options)
```
where the `options` value is an object with the following type and properties:
```ts
interface AuthOptions {
securityName?: string
verifyOptions?: jwt.VerifyOptions & { complete?: false }
jwksUri: () => Promise
getAccessToken: (req: express.Request) => Promise
getScopesFromToken: (decoded: string | jwt.JwtPayload) => Promise
tryRefreshTokens: (req: express.Request) => Promise
}
```
| property | required | description |
| ------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| jwksUri | `true` | Resolves to the `uri` for your identity providers `jwks` configuration |
| getAccessToken | `true` | Resolves a JWT from the `Request`. For example this may come from an `authorization` header or a `cookie` based on requirements |
| getScopesFromToken | `true` | Resolves to an array of OAuth scopes that the provided token supports |
| securityName | `false` | `OpenAPI` Security scheme name to be secured |
| verifyOptions | `false` | `jsonwebtoken` verification options. See the [jsonwebtoken documentation](https://www.npmjs.com/package/jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback) for details |
| tryRefreshTokens | `false` | Performs a token refresh. Resolves to `true` if the refressh succeeded otherwise `false`. By default this always resolves to `false` |
## Example
An example implementation of using the OAuth client-credential flow to authenticate a machine-to-machine (m2m) API is included in the package repository. This consists of two parts, a pre-configured `Keycloak` instance which can be instantiated with `docker compose` to act as our identity provider and an example application under [./example](./example) which implements to `tsoa` server. For further information please see the [tsoa authentication documentation](https://tsoa-community.github.io/docs/authentication.html) and our authentication handler example at [./example/authentication.ts](./example/authentication.ts).
To get started first bring up the `Keycloak` instance by executing from the repository root:
```sh
docker compose up -d
```
This will automatically pre-configure a client called `example` with client secret `example`. We can then fetch a m2m token by executing:
```sh
curl --request POST \
--url 'http://localhost:3080/realms/example/protocol/openid-connect/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data client_id=example \
--data client_secret=example
```
This will return a JSON object with a JWT auth token in the `access_token` property that takes the form like `eyJhbGci...r8TIOfRQ`.
The example server can then be run with:
```sh
npm run example
```
This server listens on port 3000 and exposes two routes `/authenticated` and `/unauthenticated` where only the first route requires an auth token. So we can for example call
```sh
curl http://localhost:3000/unauthenticated
```
which should return something like
```json
{ "message": "This route is unauthenticated", "authenticated": false }
```
But calling the authenticated route (`curl http://localhost:3000/authenticated`) in the same was will return an error
```json
{ "message": "unauthenticated" }
```
Providing the JWT auth token as part of an authentication header:
```sh
curl http://localhost:3000/authenticated --header 'authorization: bearer eyJhbGci...r8TIOfRQ'
```
causes the call to succeed:
```json
{ "message": "This route is authenticated", "authenticated": true }
```