Skip to content

NestJS JWT Authentication

JSON Web Tokens let Nest APIs authenticate clients without server-side sessions. This lesson covers issuing tokens with @nestjs/jwt and verifying them with a Passport JWT strategy.

Issuing a JWT on Login

JwtModule provides JwtService for signing and verifying tokens. After validating credentials, AuthService signs a payload (commonly sub user id and email) and returns the access token to the client.

@Injectable()
export class AuthService {
  constructor(private jwtService: JwtService, private usersService: UsersService) {}

  async login(user: User) {
    const payload = { sub: user.id, email: user.email };
    return { access_token: await this.jwtService.signAsync(payload) };
  }
}

Keep JWT payloads small and non-sensitive. Do not put passwords or secrets inside the token.

JWT Strategy Verification

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(config: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: config.get<string>('JWT_SECRET'),
    });
  }

  validate(payload: { sub: number; email: string }) {
    return { userId: payload.sub, email: payload.email };
  }
}
  • ExtractJwt.fromAuthHeaderAsBearerToken() reads Authorization: Bearer ....
  • secretOrKey must match the secret used when signing.
  • validate() runs after signature/expiry checks succeed.
  • Protect routes with @UseGuards(JwtAuthGuard).

JWT Nest Cheatsheet

Essential JWT pieces in a Nest app.

API Purpose
JwtModule.register({ secret, signOptions }) Configure signing defaults
jwtService.signAsync(payload) Create an access token
passport-jwt Strategy Verify incoming bearer tokens
AuthGuard('jwt') Protect a route with JWT
expiresIn Limit token lifetime (e.g. 15m)

Configuring JwtModule From ConfigService

Prefer JwtModule.registerAsync with ConfigService so secrets are not hard-coded in module files.

JwtModule.registerAsync({
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ({
    secret: config.get<string>('JWT_SECRET'),
    signOptions: { expiresIn: '15m' },
  }),
})

Where Clients Store Tokens

SPAs often use memory or httpOnly cookies. Mobile apps store tokens in secure storage. Document your choice and mitigate XSS/CSRF accordingly.

Common Mistakes

  • Using a weak or hard-coded JWT secret.
  • Setting very long expiresIn without refresh tokens.
  • Putting PII or permissions that change frequently inside a long-lived JWT.
  • Forgetting ignoreExpiration: false and accepting expired tokens accidentally.

Key Takeaways

  • JwtService signs tokens; Passport JWT strategy verifies them on protected routes.
  • Keep payloads minimal and secrets in configuration.
  • Short-lived access tokens reduce risk if a token leaks.
  • Use registerAsync to load secrets from ConfigService.

Pro Tip

Include a token version or jti claim if you need forced logout / revoke-all-sessions later without waiting for natural expiry.