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

# Add JWT Authentication to Your Hapi API

Secure your Hapi API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Hapi Backend Code

```javascript
const Hapi = require("@hapi/hapi");
const jwt = require("jsonwebtoken");
const jwksClient = require("jwks-rsa");

const ISSUER = "https://my-api-a32f34.zuplo.api/__zuplo/issuer";

const client = jwksClient({
  jwksUri: `${ISSUER}/.well-known/jwks.json`,
  cache: true,
  cacheMaxAge: 600000,
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    if (err) return callback(err);
    callback(null, key.getPublicKey());
  });
}

const jwtAuthScheme = () => {
  return {
    authenticate: async (request, h) => {
      const authorization = request.headers.authorization;
      if (!authorization || !authorization.startsWith("Bearer ")) {
        throw Hapi.boom.unauthorized("No token provided");
      }

      const token = authorization.slice(7);

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

        return h.authenticated({ credentials: { user: decoded } });
      } catch (err) {
        throw Hapi.boom.unauthorized("Invalid token: " + err.message);
      }
    },
  };
};

const init = async () => {
  const server = Hapi.server({ port: 3000, host: "localhost" });

  server.auth.scheme("jwt", jwtAuthScheme);
  server.auth.strategy("jwt-auth", "jwt");

  server.route({
    method: "GET",
    path: "/protected",
    options: { auth: "jwt-auth" },
    handler: (request, h) => {
      return {
        message: "Access granted",
        user: request.auth.credentials.user,
      };
    },
  });

  await server.start();
  console.log("Server running on %s", server.info.uri);
};

init();
```

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