---
title: "Add JWT Authentication to Your undefined API"
description: undefined
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/rust/rocket/jwt-backend"
framework: undefined
language: undefined
authStrategy: "JWT with JWKS"
pageType: use-case
---

# Add JWT Authentication to Your undefined API



## How Zuplo Handles It

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

## undefined Backend Code

```rust
use rocket::{get, routes, Rocket, Route, request::{self, FromRequest, Request}, http::Status};
use rocket::http::hyper::header::AUTHORIZATION;
use rocket::async_trait;
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, jwk::JwkSet};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use rocket::tokio::sync::RwLock;

const ISSUER: &str = "https://my-api-a32f34.zuplo.api/__zuplo/issuer";
const JWKS_URI: &str = "https://my-api-a32f34.zuplo.api/__zuplo/issuer/.well-known/jwks.json";

#[derive(Debug, Deserialize)]
struct Claims {
    sub: String,
    // Add other claims fields if needed
}

#[derive(Debug)]
struct JwtToken(pub Claims);

#[async_trait]
impl<'r> FromRequest<'r> for JwtToken {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, ()> {
        let keys = request.rocket().state::<Arc<RwLock<JwkSet>>>().expect("JWKS not initialized");

        let auth_header = request.headers().get_one(AUTHORIZATION.as_str());
        if let Some(token) = auth_header.and_then(|h| h.strip_prefix("Bearer ")) {
            let validation = Validation {
                iss: Some(ISSUER.to_string()),
                algorithms: vec![Algorithm::RS256],
                ..Validation::default()
            };

            let jwks = keys.read().await;
            for jwk in &jwks.keys {
                if let Ok(decoding_key) = DecodingKey::from_jwk(jwk) {
                    if let Ok(decoded) = decode::<Claims>(&token, &decoding_key, &validation) {
                        return request::Outcome::Success(JwtToken(decoded.claims));
                    }
                }
            }
        }

        request::Outcome::Failure((Status::Unauthorized, ()))
    }
}

#[get("/protected")]
fn protected_route(_user: JwtToken) -> &'static str {
    "Access granted"
}

async fn fetch_jwks() -> Result<JwkSet, reqwest::Error> {
    let client = Client::new();
    let res = client.get(JWKS_URI).send().await?.json::<JwkSet>().await?;
    Ok(res)
}

#[rocket::main]
async fn main() {
    let jwks = fetch_jwks().await.expect("Failed to fetch JWKS");
    let jwks = Arc::new(RwLock::new(jwks));

    let _ = rocket::build()
        .manage(jwks)
        .mount("/", routes![protected_route])
        .launch()
        .await;
}
```

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