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

# Add JWT Authentication to Your LoopBack API

Secure your LoopBack API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## LoopBack Backend Code

```typescript
import { Provider, inject, ValueOrPromise } from "@loopback/context";
import { Request, HttpErrors } from "@loopback/rest";
import {
  AuthenticationBindings,
  AuthenticationStrategy,
} from "@loopback/authentication";
import * as jwksRsa from "jwks-rsa";
import * as jwt from "jsonwebtoken";

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

export class JwtStrategyProvider implements Provider<AuthenticationStrategy> {
  constructor(@inject(AuthenticationBindings.METADATA) private metadata: any) {}

  value(): ValueOrPromise<AuthenticationStrategy> {
    return new JwtAuthenticationStrategy();
  }
}

class JwtAuthenticationStrategy implements AuthenticationStrategy {
  name = "jwt";

  async authenticate(request: Request) {
    const token = this.extractCredentials(request);

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

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

    return new Promise((resolve, reject) => {
      jwt.verify(
        token,
        getKey,
        { issuer: ISSUER, algorithms: ["RS256"] },
        (err, decoded) => {
          if (err) {
            return reject(
              new HttpErrors.Unauthorized(`Invalid token: ${err.message}`),
            );
          }
          resolve(decoded);
        },
      );
    });
  }

  extractCredentials(request: Request): string {
    if (!request.headers.authorization) {
      throw new HttpErrors.Unauthorized("Authorization header is missing");
    }

    const authHeaderValue = request.headers.authorization;
    if (!authHeaderValue.startsWith("Bearer ")) {
      throw new HttpErrors.Unauthorized(
        "Authorization header is not of type Bearer",
      );
    }

    const parts = authHeaderValue.split(" ");
    if (parts.length !== 2) {
      throw new HttpErrors.Unauthorized(
        "Authorization header value has too many parts.",
      );
    }
    const token = parts[1];
    return token;
  }
}

// In your application setup
import { AuthenticationComponent } from "@loopback/authentication";
import { Application } from "@loopback/core";

const app = new Application({
  components: [AuthenticationComponent],
  providers: {
    "authentication.strategies.jwt": JwtStrategyProvider,
  },
});

// Use the strategy in a controller
import { get } from "@loopback/rest";
import { authenticate } from "@loopback/authentication";

export class MyController {
  @get("/protected")
  @authenticate("jwt")
  async secureEndpoint() {
    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)
