メインコンテンツまでスキップ

Go JWT Validation Example

⚠️ 重要なお知らせ: これはデモンストレーションのための基本的な例です。実運用で使用する場合は、ソフトウェアスタック、セキュリティ要件、およびデプロイ環境に特化したベストプラクティスを調査して実装してください。常に組織のセキュリティガイドラインに従い、確立されたJWTライブラリやフレームワークの使用を検討してください。

📝 注記: この例は教育目的でJWKSのダウンロードとファイルキャッシングを示しています。実運用環境では、インフラストラクチャに基づいて、構成管理、環境変数、またはお好みのキャッシング戦略を使用してJWKSキー管理を実装することを選択できます。

この例は、Goを使用してRokt JWTトークンを検証する方法を示しています。

前提条件前提条件 への直接リンク

必要なパッケージをインストールします:

go get github.com/golang-jwt/jwt/v5

完全な例完全な例 への直接リンク

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.WithLeeway(60*time.Second)) // Allow 1 minute clock skew

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 24 hours old)
if info, err := os.Stat(cacheFile); err == nil {
if time.Since(info.ModTime()) < 24*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)
}

入出力例入出力例 への直接リンク

入力入力 への直接リンク

  • JWTトークン: 概要ページからテストトークンをコピー
  • 公開鍵ソース: https://public-api.rokt.com/.well-known/jwks.json

出力出力 への直接リンク

=== 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

実行方法実行方法 への直接リンク

  1. コードをrokt_jwt_validator.goに保存
  2. 依存関係をインストール: go mod init rokt-validator && go get github.com/golang-jwt/jwt/v5
  3. 実行: go run rokt_jwt_validator.go

go.modを使用した代替実装go.modを使用した代替実装 への直接リンク

go.modファイルを作成:

module rokt-validator

go 1.21

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

注意事項注意事項 への直接リンク

  • 公開鍵はRoktのJWKSエンドポイントから取得されます

  • 例では署名検証にECDSA-256 (ES256)アルゴリズムを使用しています

  • パフォーマンスのために公開鍵をキャッシュすることを検討してください

  • Goの標準ライブラリは優れた暗号化サポートを提供します

この記事は役に立ちましたか?