NestJS¶
Protect a NestJS API with Authany using the @authgear/nestjs SDK. The SDK validates Authany JWT access tokens offline (via OIDC discovery and JWKS) and gives you a NestJS module, an authentication guard, and decorators — so protecting a route takes just a few lines.
A complete example application is available at authgear/authgear-example-nestjs.
Note
This SDK is for the resource server side — it verifies the access tokens your API receives. It does not perform the login flow. Your users log in through a separate client (a Single-Page App, a mobile app, or any OAuth client), which then calls your NestJS API with the access token.
What you will build:
- A public route (
GET /health) that needs no token - A protected route (
GET /me) that returns the authenticated user's claims
Setting Up Your Application in Authany¶
Step 1: Enable JWT access tokens¶
The SDK validates JWT access tokens offline, so the application that issues the tokens your API will accept must issue JWTs.
- Sign in to the Authany Portal
- Select your Project, then go to Applications and open the application your client uses to log in (or create one — e.g. a Single Page Application)
- Under the Access Token section, turn on Issue JWT as access token
- Note down your Endpoint (e.g.
https://your-project.authanyid.com) and Client ID — you will need these shortly - Click Save
Warning
Without Issue JWT as access token, Authany issues opaque access tokens, which this SDK cannot validate offline. Requests would be rejected with 401.
Building Your NestJS Application¶
Step 1: Create a NestJS Project¶
Step 2: Install the Authany SDK¶
This also installs @nestjs/config, which we use to read configuration from the environment:
Step 3: Configure Environment Variables¶
Create a .env file in the project root:
Note
AUTHGEAR_CLIENT_ID is optional. When set, the SDK additionally asserts that the token's client_id claim matches it.
Step 4: Register the Authany Module¶
Register AuthgearModule in your root module. Setting global: true registers the guard as a global guard, so every route is protected by default unless explicitly marked public.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AuthgearModule } from '@authgear/nestjs';
import { AppController } from './app.controller';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
AuthgearModule.forRootAsync({
global: true,
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
endpoint: config.getOrThrow<string>('AUTHGEAR_ENDPOINT'),
clientID: config.get<string>('AUTHGEAR_CLIENT_ID'),
}),
}),
],
controllers: [AppController],
})
export class AppModule {}
Note
If your configuration is static, you can use AuthgearModule.forRoot({ endpoint: '...', global: true }) instead of forRootAsync.
Step 5: Protect Your Routes¶
With the guard registered globally, mark public routes with @Public(). Read the authenticated user with the @CurrentUser() parameter decorator.
// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { Public, CurrentUser, AuthgearClaims } from '@authgear/nestjs';
@Controller()
export class AppController {
// Public — no token required
@Public()
@Get('health')
health() {
return { status: 'ok' };
}
// Protected — requires a valid Authgear access token
@Get('me')
me(@CurrentUser() user: AuthgearClaims) {
return {
sub: user.sub,
isVerified: user.isVerified,
isAnonymous: user.isAnonymous,
};
}
}
AuthgearClaims exposes the common claims (sub, iss, aud, clientID, isVerified, isAnonymous, canReauthenticate) plus the full decoded payload as raw for any custom claims.
Note
Prefer to protect routes individually instead of globally? Omit global: true and apply the guard per controller or handler with @UseGuards(AuthgearAuthGuard).
Running the Application¶
The API listens on http://localhost:3000.
Testing the Integration¶
The public route works without a token:
The protected route is rejected without a valid token:
curl -i http://localhost:3000/me
# 401 {"message":"Missing bearer token","error":"Unauthorized","statusCode":401}
To call the protected route, send an Authany access token as a Bearer token:
curl -i http://localhost:3000/me \
-H "Authorization: Bearer <ACCESS_TOKEN>"
# 200 {"sub":"...","isVerified":true,"isAnonymous":false}
Note
Obtain an access token by logging a user in through a client application. The example project includes a small frontend that signs in and calls the protected API for you. To build your own client, see the Single-Page App or Native/Mobile App guides.
Module Options¶
forRoot() and the object returned by the forRootAsync() factory accept:
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
endpoint |
string |
✓ | — | Authany project endpoint. Used for OIDC discovery and JWKS. |
clientID |
string |
— | If set, the verifier also asserts the token's client_id claim. |
|
global |
boolean |
false |
Register the guard as a global APP_GUARD so all routes are protected. |
|
jwksCacheMaxAge |
number |
— | JWKS cache max age in milliseconds. | |
clockToleranceSeconds |
number |
0 |
Leeway in seconds for exp/iat checks. |
You can also inject AuthgearTokenService to verify a token outside of the guard.
Next Steps¶
- JWT access token reference — the full list of claims
- Validate JWT in your backend — the framework-agnostic approach
@authgear/nestjsdocumentation & API reference