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

# Add JWT Authentication to Your Hono API

Secure your Hono API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Hono Backend Code

```typescript
import { Hono } from "hono";
import { jwt } from "jsonwebtoken";
import { jwtVerify } from "jose";
import axios from "axios";

const app = new Hono();

// Replace with your actual deployment name or custom domain
const ISSUER = "https://my-api-a32f34.zuplo.api/__zuplo/issuer";
const JWKS_URI = `${ISSUER}/.well-known/jwks.json`;

let jwks: { [key: string]: string } = {};

async function fetchJWKS() {
  try {
    const response = await axios.get(JWKS_URI);
    const keys = response.data.keys;
    keys.forEach((key: any) => {
      jwks[key.kid] = key.x5c[0]; // Use the appropriate property
    });
  } catch (error) {
    console.error("Error fetching JWKS:", error);
  }
}

// Fetch the JWKS initially
fetchJWKS();

// Refresh keys every 10 minutes
setInterval(fetchJWKS, 10 * 60 * 1000);

const validateJwt = async (c: any, next: any) => {
  const token = c.req.headers.authorization?.replace("Bearer ", "");

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

  try {
    const decodedHeader = (jwt.decode(token, { complete: true }) as any).header;
    const key = jwks[decodedHeader.kid];

    if (!key) {
      throw new Error("Key not found");
    }

    await jwtVerify(token, key, {
      issuer: ISSUER,
      algorithms: ["RS256"],
    });

    await next();
  } catch (err) {
    return c.json({ error: "Invalid token", details: err.message }, 401);
  }
};

// Example route protected by JWT
app.get("/protected", validateJwt, (c) => {
  return c.json({ message: "Access granted" });
});

export default app;
```

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