---
title: "Add JWT Authentication to Your AdonisJS API"
description: "Secure your AdonisJS API using JWT authentication with JWKS."
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/typescript/adonisjs/jwt-backend"
framework: "AdonisJS"
language: "TypeScript"
authStrategy: "JWT with JWKS"
pageType: use-case
---

# Add JWT Authentication to Your AdonisJS API

Secure your AdonisJS API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## AdonisJS Backend Code

```typescript
import { HttpContextContract } from "@ioc:Adonis/Core/HttpContext";
import jwt from "jsonwebtoken";
import jwksClient from "jwks-rsa";

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

// Create a JWKS client to fetch public keys
const client = jwksClient({
  jwksUri: `${ISSUER}/.well-known/jwks.json`,
  cache: true,
  cacheMaxAge: 600000, // 10 minutes
});

// Function to get the signing key
async function getKey(header: jwt.JwtHeader): Promise<string> {
  const key = await client.getSigningKeyAsync(header.kid);
  return key.getPublicKey();
}

// Middleware to validate JWT
export async function validateJwt(
  { request, response }: HttpContextContract,
  next: () => Promise<void>,
) {
  try {
    const authHeader = request.header("authorization");
    const token = authHeader?.replace("Bearer ", "");

    if (!token) {
      return response.status(401).json({ error: "No token provided" });
    }

    const decoded = await new Promise((resolve, reject) => {
      jwt.verify(
        token,
        (header, callback) => {
          getKey(header)
            .then((key) => callback(null, key))
            .catch(callback);
        },
        { issuer: ISSUER, algorithms: ["RS256"] },
        (err, decoded) => {
          if (err) {
            reject(err);
          } else {
            resolve(decoded);
          }
        },
      );
    });

    request["user"] = decoded;
    await next();
  } catch (err) {
    return response
      .status(401)
      .json({ error: "Invalid token", details: err.message });
  }
}

// Example usage in a controller
export default class ProtectedController {
  public async show({ request, response }: HttpContextContract) {
    response.json({
      message: "Access granted",
      user: request["user"],
    });
  }
}

// Register the middleware in start/kernel.ts
// import { validateJwt } from 'path/to/your/middleware'
// Server.middleware.registerNamed({
//   jwtAuth: validateJwt
// })

// Apply middleware to routes in start/routes.ts
// Route.get('/protected', 'ProtectedController.show').middleware('jwtAuth')
```

## 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)
