---
title: "Add JWT Authentication to Your undefined API"
description: undefined
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/typescript/nestjs/jwt-backend"
framework: undefined
language: undefined
authStrategy: "JWT with JWKS"
pageType: use-case
---

# Add JWT Authentication to Your undefined API



## How Zuplo Handles It

Let Zuplo issue short-lived JWTs signed with a JWKS your undefined backend can verify — no long-lived API keys touch your origin.

## undefined Backend Code

```typescript
import {
  Injectable,
  CanActivate,
  ExecutionContext,
  UnauthorizedException,
} from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { JwksClient } from "jwks-rsa";
import { promisify } from "util";
import { Request } from "express";

// Replace with your actual Zuplo deployment name or custom domain
const ISSUER = "https://my-api-a32f34.zuplo.api/__zuplo/issuer";

@Injectable()
export class JwtAuthGuard implements CanActivate {
  private jwksClient: JwksClient;
  private getSigningKey: any;

  constructor(private readonly jwtService: JwtService) {
    this.jwksClient = new JwksClient({
      jwksUri: `${ISSUER}/.well-known/jwks.json`,
      cache: true,
      cacheMaxAge: 600000, // 10 minutes
    });
    this.getSigningKey = promisify(this.jwksClient.getSigningKey);
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    const token = this.extractTokenFromHeader(request);

    if (!token) {
      throw new UnauthorizedException("No token provided");
    }

    try {
      const decodedToken = await this.verifyToken(token);
      request["user"] = decodedToken;
      return true;
    } catch (error) {
      throw new UnauthorizedException(`Invalid token: ${error.message}`);
    }
  }

  private extractTokenFromHeader(request: Request): string | null {
    const authHeader = request.headers.authorization;
    if (authHeader && authHeader.startsWith("Bearer ")) {
      return authHeader.replace("Bearer ", "");
    }
    return null;
  }

  private async verifyToken(token: string) {
    const decodedToken: any = this.jwtService.decode(token, { complete: true });

    const key = await this.getSigningKey(decodedToken.header.kid);
    const signingKey = key.getPublicKey();

    return this.jwtService.verifyAsync(token, {
      secret: signingKey,
      issuer: ISSUER,
      algorithms: ["RS256"],
    });
  }
}

// In your controller
import { Controller, Get, UseGuards } from "@nestjs/common";

@Controller("protected")
export class ProtectedController {
  @Get()
  @UseGuards(JwtAuthGuard)
  getProtectedResource() {
    return { message: "Access granted" };
  }
}
```

## Example Request

```bash
curl -X GET \
  'https://your-api.zuplo.dev/your-route' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

## Learn More

- [API Key Authentication on Zuplo](https://zuplo.com/docs/policies/api-key-auth-inbound)
- [JWT Authentication on Zuplo](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound)
- [All use cases](https://zuplo.com/use-cases)
