Exemple de Validation JWT en Go
⚠️ Avis Important : Ceci est un exemple basique à des fins de démonstration uniquement. Pour une utilisation en production, veuillez rechercher et mettre en œuvre les meilleures pratiques spécifiques à votre pile logicielle, vos exigences de sécurité et votre environnement de déploiement. Suivez toujours les directives de sécurité de votre organisation et envisagez d'utiliser des bibliothèques et frameworks JWT établis.
📝 Remarque : Cet exemple démontre le téléchargement de JWKS et la mise en cache de fichiers à des fins éducatives. Dans les environnements de production, vous pouvez choisir de gérer les clés JWKS différemment en fonction de votre infrastructure - comme en utilisant la gestion de configuration, des variables d'environnement, ou votre stratégie de mise en cache préférée.
Cet exemple démontre comment valider les jetons JWT de Rokt en utilisant Go.
Prérequis
Installez les packages requis :
go get github.com/golang-jwt/jwt/v5
Exemple Complet
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 représente la structure JSON Web Key Set
type JWKS struct {
Keys []JWK `json:"keys"`
}
// JWK représente la structure JSON Web Key
type JWK struct {
Kid string `json:"kid"`
Kty string `json:"kty"`
Crv string `json:"crv"`
X string `json:"x"`
Y string `json:"y"`
}
// ReferralClaims représente les données de référence dans les revendications JWT
type ReferralClaims struct {
CampaignID string `json:"cid"`
CreativeID string `json:"crid"`
RCLID string `json:"rclid"`
jwt.RegisteredClaims
}
// ValidateReferralToken valide le jeton JWT et extrait les données de référence
func ValidateReferralToken(jwtToken, jwksJson string) (*ReferralClaims, error) {
// Analyser JWKS
var jwks JWKS
if err := json.Unmarshal([]byte(jwksJson), &jwks); err != nil {
return nil, fmt.Errorf("échec de l'analyse de JWKS : %v", err)
}
if len(jwks.Keys) == 0 {
return nil, fmt.Errorf("aucune clé trouvée dans JWKS")
}
// Obtenir la première clé (en supposant une seule clé pour simplifier)
jwk := jwks.Keys[0]
// Décoder les coordonnées encodées en base64url
xBytes, err := base64.RawURLEncoding.DecodeString(jwk.X)
if err != nil {
return nil, fmt.Errorf("échec du décodage de la coordonnée X : %v", err)
```go
}
yBytes, err := base64.RawURLEncoding.DecodeString(jwk.Y)
if err != nil {
return nil, fmt.Errorf("échec du décodage de la coordonnée Y : %v", err)
}
// Créer une clé publique ECDSA
publicKey := &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: new(big.Int).SetBytes(xBytes),
Y: new(big.Int).SetBytes(yBytes),
}
// Analyser et valider le jeton JWT
token, err := jwt.ParseWithClaims(jwtToken, &ReferralClaims{}, func(token *jwt.Token) (interface{}, error) {
// Vérifier la méthode de signature
if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
return nil, fmt.Errorf("méthode de signature inattendue : %v", token.Header["alg"])
}
return publicKey, nil
}, jwt.WithLeeway(60*time.Second)) // Permettre un décalage d'horloge de 1 minute
if err != nil {
return nil, fmt.Errorf("échec de l'analyse du JWT : %v", err)
}
if claims, ok := token.Claims.(*ReferralClaims); ok && token.Valid {
return claims, nil
}
return nil, fmt.Errorf("jeton invalide")
}
func downloadAndCacheJWKS(jwksURL, cacheFile string) (string, error) {
// Vérifier si le fichier de cache existe et est récent (moins de 24 heures)
if info, err := os.Stat(cacheFile); err == nil {
if time.Since(info.ModTime()) < 24*time.Hour {
fmt.Printf("Utilisation du JWKS mis en cache depuis : %s\n", cacheFile)
data, err := os.ReadFile(cacheFile)
if err != nil {
return "", fmt.Errorf("échec de la lecture du fichier de cache : %v", err)
}
return string(data), nil
}
}
// Télécharger le JWKS
fmt.Printf("Téléchargement du JWKS depuis : %s\n", jwksURL)
resp, err := http.Get(jwksURL)
if err != nil {
return "", fmt.Errorf("échec du téléchargement du JWKS : %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("échec du téléchargement du JWKS : HTTP %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("échec de la lecture du corps de la réponse : %v", err)
}
// Mettre en cache le JWKS
if err := os.WriteFile(cacheFile, body, 0644); err != nil {
fmt.Printf("Avertissement : échec de la mise en cache du JWKS : %v\n", err)
} else {
fmt.Printf("JWKS mis en cache dans : %s\n", cacheFile)
}
return string(body), nil
}
func main() {
// Exemple de jeton JWT de Rokt
// Copier le jeton de test depuis la page d'aperçu
sampleToken := "PASTE_TEST_TOKEN_HERE"
// URL du point de terminaison JWKS
jwksURL := "https://public-api.rokt.com/.well-known/jwks.json"
``````go
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()
// Télécharger et mettre en cache JWKS
jwksJson, err := downloadAndCacheJWKS(jwksURL, jwksCacheFile)
if err != nil {
fmt.Printf("❌ Échec du téléchargement de JWKS: %v\n", err)
return
}
fmt.Println("JWKS téléchargé et mis en cache avec succès")
// Extraire les coordonnées de la clé publique de JWKS
var jwks JWKS
if err := json.Unmarshal([]byte(jwksJson), &jwks); err != nil {
fmt.Printf("❌ Échec de l'analyse de JWKS: %v\n", err)
return
}
if len(jwks.Keys) == 0 {
fmt.Println("❌ Aucune clé trouvée dans JWKS")
return
}
key := jwks.Keys[0]
// Valider le jeton
claims, err := ValidateReferralToken(sampleToken, jwksJson)
if err != nil {
log.Fatalf("Échec de la validation du jeton: %v", err)
}
fmt.Println("✅ Validation du jeton réussie!")
fmt.Printf("ID de la campagne: %s\n", claims.CampaignID)
fmt.Printf("ID créatif: %s\n", claims.CreativeID)
fmt.Printf("RCLID: %s\n", claims.RCLID)
fmt.Printf("Émis à: %v\n", claims.IssuedAt)
}
#```# Exemple d'Entrée/Sortie
Entrée
- Jeton JWT : Copiez le jeton de test depuis la page d'aperçu
- Source de la clé publique :
https://public-api.rokt.com/.well-known/jwks.json
Sortie
=== Validateur JWT Go ===
Jeton : eyJhbGciOiJFUzI1NiIsImtpZCI6InJva3Qtc2lnbmluZy1rZXkiLCJ0eXAiOiJKV1QifQ...
URL JWKS : https://public-api.rokt.com/.well-known/jwks.json
Téléchargement de JWKS depuis : https://public-api.rokt.com/.well-known/jwks.json
JWKS mis en cache dans : jwks_cache.json
JWKS téléchargé et mis en cache avec succès
✅ Validation du jeton réussie !
ID de la campagne : 3436085368692408324
ID créatif : 3437732754935906308
RCLID : 7db958dbd232247a4a8285a34d22fe0f4e9affa463bf5ee54e26721ab0df0e23
Émis à : 2025-08-20 15:10:01 +1000 AEST
Comment Exécuter
- Enregistrez le code dans
rokt_jwt_validator.go - Installez les dépendances :
go mod init rokt-validator && go get github.com/golang-jwt/jwt/v5 - Exécutez :
go run rokt_jwt_validator.go
Implémentation Alternative avec go.mod
Créez un fichier go.mod :
module rokt-validator
go 1.21
require github.com/golang-jwt/jwt/v5 v5.0.0
Remarques
-
La clé publique est récupérée depuis le point de terminaison JWKS de Rokt
-
L'exemple utilise l'algorithme ECDSA-256 (ES256) pour la vérification de signature
-
Envisagez de mettre en cache la clé publique pour améliorer les performances
-
La bibliothèque standard de Go offre un excellent support cryptographique