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

# Add JWT Authentication to Your Tide API

Secure your Tide API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Tide Backend Code

```rust
use async_std::task;
use tide::{Request, Response, StatusCode};
use tide::utils::After;
use jsonwebtoken::{decode, decode_header, Algorithm, DecodingKey, Validation};
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

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, Serialize, Deserialize)]
pub struct Claims {
    sub: String,
    // Add more required fields
}

fn fetch_jwk(kid: &str) -> Result<DecodingKey, Box<dyn std::error::Error>> {
    let client = Client::new();
    let res = client.get(JWKS_URI).send()?;
    let jwks: HashMap<String, Vec<DecodingKey>> = res.json()?;

    if let Some(keys) = jwks.get("keys") {
        for key in keys {
            if key.kid == Some(kid.to_string()) {
                return Ok(key.to_owned());
            }
        }
    }
    Err("Key not found".into())
}

async fn validate_jwt(req: Request<()>) -> tide::Result {
    let auth_header = req.header("Authorization").and_then(|vals| vals.get(0).map(|s| s.to_string()));

    if let Some(auth_header) = auth_header {
        let token = auth_header.trim_start_matches("Bearer ");
        if let Ok(token_data) = decode_header(token) {
            if let Some(kid) = token_data.kid {
                if let Ok(decoding_key) = fetch_jwk(&kid) {
                    let mut validation = Validation::new(Algorithm::RS256);
                    validation.set_issuer(&[ISSUER]);

                    match decode::<Claims>(&token, &decoding_key, &validation) {
                        Ok(data) => {
                            req.set_ext(data.claims);
                            return Ok(Response::new(StatusCode::Ok));
                        }
                        Err(err) => return Err(tide::Error::from_str(StatusCode::Unauthorized, format!("Invalid token: {:?}", err))),
                    }
                }
            }
        }
    }

    Err(tide::Error::from_str(StatusCode::Unauthorized, "No valid authorization header found"))
}

#[async_std::main]
async fn main() -> tide::Result<()> {
    let mut app = tide::new();

    app.with(After(|res: Response| async {
        if res.status().is_client_error() || res.status().is_server_error() {
            Ok(res.set_body("Unauthorized"))
        } else {
            Ok(res)
        }
    }));

    app.at("/protected").get(|req: Request<()>| async move {
        validate_jwt(req).await?;
        Ok(Response::new(StatusCode::Ok).body_json(&Claims { sub: "user".into() })?)
    });

    app.listen("127.0.0.1:8080").await?;
    Ok(())
}
```

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