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

# Add JWT Authentication to Your Beego API

Secure your Beego API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Beego Backend Code

```go
package main

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/astaxie/beego"
	"github.com/dgrijalva/jwt-go"
	"gopkg.in/square/go-jose.v2/jwk"
)

// Constants
const Issuer = "https://my-api-a32f34.zuplo.api/__zuplo/issuer"
const JwksURL = Issuer + "/.well-known/jwks.json"

// JWKSClient fetches and caches the JWKS
type JWKSClient struct {
	jwks *jwk.Set
}

// NewJWKSClient initializes the JWKS client with caching logic
func NewJWKSClient() (*JWKSClient, error) {
	resp, err := http.Get(JwksURL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var jwks jwk.Set
	if err := json.NewDecoder(resp.Body).Decode(&jwks); err != nil {
		return nil, err
	}

	return &JWKSClient{jwks: &jwks}, nil
}

// GetKey retrieves the public key by kid
func (j *JWKSClient) GetKey(kid string) (interface{}, error) {
	keys := j.jwks.LookupKeyID(kid)
	if len(keys) == 0 {
		return nil, errors.New("key not found")
	}
	publicKey, err := keys[0].Materialize()
	if err != nil {
		return nil, err
	}
	return publicKey, nil
}

// JWTMiddleware validates the JWT token
func JWTMiddleware(jwksClient *JWKSClient) beego.FilterFunc {
	return func(ctx *context.Context) {
		authHeader := ctx.Input.Header("Authorization")
		if authHeader == "" {
			ctx.Output.SetStatus(http.StatusUnauthorized)
			ctx.Output.Body([]byte("No token provided"))
			return
		}

		tokenString := strings.TrimPrefix(authHeader, "Bearer ")
		token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
			// Check the signing method
			if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
				return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
			}

			kid, ok := token.Header["kid"].(string)
			if !ok {
				return nil, errors.New("kid not found in token header")
			}

			return jwksClient.GetKey(kid)
		})
		if err != nil {
			ctx.Output.SetStatus(http.StatusUnauthorized)
			ctx.Output.Body([]byte("Invalid token: " + err.Error()))
			return
		}

		if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
			// Access your claims here if needed
			ctx.Input.SetData("user", claims)
		} else {
			ctx.Output.SetStatus(http.StatusUnauthorized)
			ctx.Output.Body([]byte("Invalid token claims"))
		}
	}
}

func main() {
	// Initialize JWKS Client
	jwksClient, err := NewJWKSClient()
	if err != nil {
		panic("Failed to initialize JWKS client: " + err.Error())
	}

	// Register the JWT middleware
	beego.InsertFilter("/protected/*", beego.BeforeRouter, JWTMiddleware(jwksClient))

	// Add a protected route
	beego.Router("/protected/data", &ProtectedController{})

	// Run the server
	beego.Run()
}

// ProtectedController handles requests to protected routes
type ProtectedController struct {
	beego.Controller
}

func (p *ProtectedController) Get() {
	user := p.Ctx.Input.GetData("user")
	p.Data["json"] = map[string]interface{}{
		"message": "Access granted",
		"user":    user,
	}
	p.ServeJSON()
}
```

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