---
title: "Add JWT Authentication to Your Gorilla Mux API"
description: "Secure your Gorilla Mux API using JWT authentication with JWKS."
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/go/gorillamux/jwt-backend"
framework: "Gorilla Mux"
language: "Go"
authStrategy: "JWT with JWKS"
pageType: use-case
---

# Add JWT Authentication to Your Gorilla Mux API

Secure your Gorilla Mux API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Gorilla Mux Backend Code

```go
package main

import (
    "fmt"
    "github.com/golang-jwt/jwt/v4"
    "github.com/gorilla/mux"
    "log"
    "net/http"
    "strings"
    "github.com/MicahParks/keyfunc"
)

const (
    issuer = "https://my-api-a32f34.zuplo.api/__zuplo/issuer"
)

var (
    keyFunc *keyfunc.JWKS
)

func init() {
    jwksURL := fmt.Sprintf("%s/.well-known/jwks.json", issuer)
    options := keyfunc.Options{
        RefreshErrorHandler: func(err error) {
            log.Printf("There was an error with the jwt.Keyfunc\nError:%s\n", err.Error())
        },
    }

    var err error
    keyFunc, err = keyfunc.Get(jwksURL, options)
    if err != nil {
        log.Fatalf("Failed to create JWKS from URL: %s\nError: %s", jwksURL, err.Error())
    }
}

func validateJWT(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        authHeader := r.Header.Get("Authorization")
        if authHeader == "" {
            http.Error(w, "No token provided", http.StatusUnauthorized)
            return
        }

        tokenString := strings.TrimPrefix(authHeader, "Bearer ")
        token, err := jwt.Parse(tokenString, keyFunc.Keyfunc)
        if err != nil || !token.Valid {
            http.Error(w, "Invalid token", http.StatusUnauthorized)
            return
        }

        claims, ok := token.Claims.(jwt.MapClaims)
        if !ok || !token.Valid {
            http.Error(w, "Invalid token claims", http.StatusUnauthorized)
            return
        }

        if claims["iss"] != issuer {
            http.Error(w, "Invalid issuer", http.StatusUnauthorized)
            return
        }

        // Pass user info to context
        r = r.WithContext(context.WithValue(r.Context(), "user", claims))
        next.ServeHTTP(w, r)
    })
}

func protectedEndpoint(w http.ResponseWriter, r *http.Request) {
    user := r.Context().Value("user")
    response := fmt.Sprintf("Access granted. User: %v", user)
    w.Write([]byte(response))
}

func main() {
    r := mux.NewRouter()

    // Protected Route
    r.Handle("/protected", validateJWT(http.HandlerFunc(protectedEndpoint)))

    http.Handle("/", r)
    log.Println("Server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
```

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