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

# Add JWT Authentication to Your Hummingbird API

Secure your Hummingbird API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Hummingbird Backend Code

```swift
import Hummingbird
import HummingbirdFoundation
import JWTKit

struct JWTPayload: JWTPayload {
    let sub: SubjectClaim
    let exp: ExpirationClaim

    func verify(using signer: JWTSigner) throws {
        try exp.verifyNotExpired()
    }
}

func createApp() -> HBApplication {
    let app = HBApplication(configuration: .init(address: .hostname("127.0.0.1", port: 8080)))

    // JWKS client setup
    let issuer = "https://my-api-a32f34.zuplo.api/__zuplo/issuer"
    let jwksURL = URL(string: "\(issuer)/.well-known/jwks.json")!
    let jwks = JWKS(remoteURL: jwksURL, cacheExpiration: .minutes(10))

    // Middleware to validate JWT
    app.middleware.add(HBMiddleware() { request, next in
        guard let token = request.headers.bearerAuthorization?.token else {
            throw HBHTTPError(.unauthorized, message: "No token provided")
        }

        do {
            let signers = JWTSigners()
            try signers.use(jwks: jwks)
            let payload = try signers.verify(token, as: JWTPayload.self)
            request.extensions.set(payload)
            return next.handle(request)
        } catch {
            throw HBHTTPError(.unauthorized, message: "Invalid token: \(error.localizedDescription)")
        }
    })

    // Protected route example
    app.router.get("protected") { request -> HBResponse in
        guard let payload: JWTPayload = request.extensions.get() else {
            throw HBHTTPError(.unauthorized, message: "Missing or invalid token")
        }
        return .init(body: .json(["message": "Access granted", "user": payload.sub.value]))
    }

    return app
}

// Start the application
let app = createApp()
try app.start()
```

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