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

# Add JWT Authentication to Your Javalin API

Secure your Javalin API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Javalin Backend Code

```java
import io.javalin.Javalin;
import io.javalin.http.Context;
import io.javalin.http.Handler;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.JwkProviderBuilder;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.RSAKeyProvider;

import java.net.URL;
import java.security.interfaces.RSAPublicKey;
import java.util.concurrent.TimeUnit;

public class JavalinJwtExample {

    private static final String ISSUER = "https://my-api-a32f34.zuplo.api/__zuplo/issuer";

    public static void main(String[] args) throws Exception {

        JwkProvider jwkProvider = new JwkProviderBuilder(new URL(ISSUER + "/.well-known/jwks.json"))
            .cached(10, 10, TimeUnit.MINUTES)
            .build();

        RSAKeyProvider keyProvider = new RSAKeyProvider() {
            @Override
            public RSAPublicKey getPublicKeyById(String keyId) {
                try {
                    return (RSAPublicKey) jwkProvider.get(keyId).getPublicKey();
                } catch (Exception e) {
                    throw new RuntimeException("Failed to get public key", e);
                }
            }

            @Override
            public RSAPublicKey getPrivateKey() {
                return null;
            }

            @Override
            public String getPrivateKeyId() {
                return null;
            }
        };

        JWTVerifier verifier = JWT.require(Algorithm.RSA256(keyProvider))
            .withIssuer(ISSUER)
            .build();

        Handler jwtHandler = ctx -> {
            String token = getBearerToken(ctx);
            if (token == null) {
                ctx.status(401).json("No token provided");
                return;
            }

            try {
                DecodedJWT jwt = verifier.verify(token);
                ctx.attribute("user", jwt.getSubject());
            } catch (Exception e) {
                ctx.status(401).json("Invalid token: " + e.getMessage());
                return;
            }
        };

        Javalin app = Javalin.create().start(7000);

        app.before("/protected", jwtHandler);

        app.get("/protected", ctx -> {
            String user = ctx.attribute("user");
            ctx.json("Access granted to " + user);
        });
    }

    private static String getBearerToken(Context ctx) {
        String authorizationHeader = ctx.header("Authorization");
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            return authorizationHeader.substring("Bearer ".length());
        }
        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)
