Skip to main content

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

Output

=== Go JWT Validator ===
Token: eyJhbGciOiJFUzI1NiIsImtpZCI6InJva3Qtc2lnbmluZy1rZXkiLCJ0eXAiOiJKV1QifQ...
JWKS URL: https://public-api.rokt.com/.well-known/jwks.json

Downloading JWKS from: https://public-api.rokt.com/.well-known/jwks.json
JWKS cached to: jwks_cache.json
JWKS downloaded and cached successfully

✅ Token validation successful!
Campaign ID: 3436085368692408324
Creative ID: 3437732754935906308
RCLID: 7db958dbd232247a4a8285a34d22fe0f4e9affa463bf5ee54e26721ab0df0e23
Issued At: 2025-08-20 15:10:01 +1000 AEST

How to Run

  1. Save the code to rokt_jwt_validator.go
  2. Install dependencies: go mod init rokt-validator && go get github.com/golang-jwt/jwt/v5
  3. Run: go run rokt_jwt_validator.go

Alternative Implementation with go.mod

Create a go.mod file:

module rokt-validator

go 1.21

require github.com/golang-jwt/jwt/v5 v5.0.0

Notes

  • The public key is retrieved from Rokt's JWKS endpoint

  • The example uses ECDSA-256 (ES256) algorithm for signature verification

  • Consider caching the public key for performance

  • Go's standard library provides excellent cryptographic support

Was this article helpful?