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

# Add JWT Authentication to Your Zuul API

Secure your Zuul API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Zuul Backend Code

```java
import com.auth0.jwk.JwkProviderBuilder;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class JWTAuthenticationFilter extends ZuulFilter {

    private static final String ISSUER = "https://my-api-a32f34.zuplo.api/__zuplo/issuer";
    private static final String JWKS_URL = ISSUER + "/.well-known/jwks.json";

    private final JwkProviderBuilder jwkProviderBuilder = new JwkProviderBuilder(JWKS_URL)
            .cached(10, 10, TimeUnit.MINUTES);

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String authorizationHeader = ctx.getRequest().getHeader("Authorization");

        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            ctx.setResponseBody("{\"error\": \"No token provided\"}");
            ctx.setSendZuulResponse(false);
            return null;
        }

        String token = authorizationHeader.replace("Bearer ", "");

        try {
            DecodedJWT jwt = JWT.decode(token);
            Algorithm algorithm = Algorithm.RSA256(jwkProviderBuilder.build().get(jwt.getKeyId()).getPublicKey(), null);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer(ISSUER)
                    .build();
            verifier.verify(token);

            ctx.set("user", jwt.getClaims());
        } catch (JWTVerificationException | Exception e) {
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            ctx.setResponseBody("{\"error\": \"Invalid token\", \"details\": \"" + e.getMessage() + "\"}");
            ctx.setSendZuulResponse(false);
        }

        return null;
    }
}
```

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