Go JWT Validation Example
⚠️ Important Notice: This is a basic example for demonstration purposes only. For production use, please research and implement best practices specific to your software stack, security requirements, and deployment environment. Always follow your organization's security guidelines and consider using established JWT libraries and frameworks.
📝 Note: This example demonstrates JWKS downloading and file caching for educational purposes. In production environments, you may choose to implement JWKS key management differently based on your infrastructure - such as using configuration management, environment variables, or your preferred caching strategy.
This example demonstrates how to validate Rokt JWT tokens using Go.
Prerequisites
Install the required packages:
go get github.com/golang-jwt/jwt/v5
Complete Example
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"math/big"
"net/http"
"os"
"strings"
"time"
"github.com/golang-jwt/jwt/v5"
)
// JWKS represents JSON Web Key Set structure
type JWKS struct {
Keys []JWK `json:"keys"`
}
// JWK represents JSON Web Key structure
type JWK struct {
Kid string `json:"kid"`
Kty string `json:"kty"`
Crv string `json:"crv"`
X string `json:"x"`
Y string `json:"y"`
}
// ReferralClaims represents the referral data in JWT claims
type ReferralClaims struct {
CampaignID string `json:"cid"`
CreativeID string `json:"crid"`
RCLID string `json:"rclid"`
jwt.RegisteredClaims
}
// ValidateReferralToken validates JWT token and extracts referral data
func ValidateReferralToken(jwtToken, jwksJson string) (*ReferralClaims, error) {
// Parse JWKS
var jwks JWKS
if err := json.Unmarshal([]byte(jwksJson), &jwks); err != nil {
return nil, fmt.Errorf("failed to parse JWKS: %v", err)
}
if len(jwks.Keys) == 0 {
return nil, fmt.Errorf("no keys found in JWKS")
}
// Get the first key (assuming single key for simplicity)
jwk := jwks.Keys[0]
// Decode base64url encoded coordinates
xBytes, err := base64.RawURLEncoding.DecodeString(jwk.X)
if err != nil {
return nil, fmt.Errorf("failed to decode X coordinate: %v", err)
}
yBytes, err := base64.RawURLEncoding.DecodeString(jwk.Y)
if err != nil {
return nil, fmt.Errorf("failed to decode Y coordinate: %v", err)
}
// Create ECDSA public key
publicKey := &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: new(big.Int).SetBytes(xBytes),
Y: new(big.Int).SetBytes(yBytes),
}
// Parse and validate JWT token
token, err := jwt.ParseWithClaims(jwtToken, &ReferralClaims{}, func(token *jwt.Token) (interface{}, error) {
// Verify signing method
if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return publicKey, nil
}, jwt.WithoutClaimsValidation()) // Disable expiration check for demo - using sample token
if err != nil {
return nil, fmt.Errorf("failed to parse JWT: %v", err)
}
if claims, ok := token.Claims.(*ReferralClaims); ok && token.Valid {
return claims, nil
}
return nil, fmt.Errorf("invalid token")
}
func downloadAndCacheJWKS(jwksURL, cacheFile string) (string, error) {
// Check if cache file exists and is recent (less than 1 hour old)
if info, err := os.Stat(cacheFile); err == nil {
if time.Since(info.ModTime()) < time.Hour {
fmt.Printf("Using cached JWKS from: %s\n", cacheFile)
data, err := os.ReadFile(cacheFile)
if err != nil {
return "", fmt.Errorf("failed to read cache file: %v", err)
}
return string(data), nil
}
}
// Download JWKS
fmt.Printf("Downloading JWKS from: %s\n", jwksURL)
resp, err := http.Get(jwksURL)
if err != nil {
return "", fmt.Errorf("failed to download JWKS: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to download JWKS: HTTP %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read response body: %v", err)
}
// Cache the JWKS
if err := os.WriteFile(cacheFile, body, 0644); err != nil {
fmt.Printf("Warning: failed to cache JWKS: %v\n", err)
} else {
fmt.Printf("JWKS cached to: %s\n", cacheFile)
}
return string(body), nil
}
func main() {
// Sample JWT token from Rokt
// Copy the test token from the Overview page
sampleToken := "PASTE_TEST_TOKEN_HERE"
// JWKS endpoint URL
jwksURL := "https://public-api.rokt.com/.well-known/jwks.json"
jwksCacheFile := "jwks_cache.json"
fmt.Println("=== Go JWT Validator ===")
fmt.Printf("Token: %s...\n", sampleToken[:50])
fmt.Printf("JWKS URL: %s\n", jwksURL)
fmt.Println()
// Download and cache JWKS
jwksJson, err := downloadAndCacheJWKS(jwksURL, jwksCacheFile)
if err != nil {
fmt.Printf("❌ Failed to download JWKS: %v\n", err)
return
}
fmt.Println("JWKS downloaded and cached successfully")
// Extract public key coordinates from JWKS
var jwks JWKS
if err := json.Unmarshal([]byte(jwksJson), &jwks); err != nil {
fmt.Printf("❌ Failed to parse JWKS: %v\n", err)
return
}
if len(jwks.Keys) == 0 {
fmt.Println("❌ No keys found in JWKS")
return
}
key := jwks.Keys[0]
// Validate the token
claims, err := ValidateReferralToken(sampleToken, jwksJson)
if err != nil {
log.Fatalf("Token validation failed: %v", err)
}
fmt.Println("✅ Token validation successful!")
fmt.Printf("Campaign ID: %s\n", claims.CampaignID)
fmt.Printf("Creative ID: %s\n", claims.CreativeID)
fmt.Printf("RCLID: %s\n", claims.RCLID)
fmt.Printf("Issued At: %v\n", claims.IssuedAt)
}
Input/Output Example
Input
- JWT Token: Copy the test token from the Overview page
- Public Key Source:
https://public-api.rokt.com/.well-known/jwks.json