// Copyright 2024 Patial Tech (Ankit Patial). // // This file is part of code.patial.tech/go/appcore, which is MIT licensed. // See http://opensource.org/licenses/MIT package jwt import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "fmt" "testing" "time" "code.patial.tech/go/appcore/crypto" ) /* -----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA9JTCYl3OQwuVTSf0PsBkmgJSt7e5Tbk3jKnB90vDqXA= -----END PUBLIC KEY----- -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIMMkYUKJ9P0gp+Rm9mR4i0KUBT9nFUzxzxjH7sC0xq/F -----END PRIVATE KEY----- */ func TestSign2(t *testing.T) { key, err := crypto.ParseEdPrivateKey([]byte(`-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIMMkYUKJ9P0gp+Rm9mR4i0KUBT9nFUzxzxjH7sC0xq/F -----END PRIVATE KEY-----`)) if err != nil { t.Fatal(err) } s, err := Sign(key, map[string]any{"name": "ankit", "age": 25}, "blackdu", time.Second) if err != nil { t.Fatal(err) } println(s) } func TestExprired(t *testing.T) { privKey, err := crypto.ParseEdPrivateKey([]byte(`-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIMMkYUKJ9P0gp+Rm9mR4i0KUBT9nFUzxzxjH7sC0xq/F -----END PRIVATE KEY-----`)) if err != nil { t.Error(err) } // payload := "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJhZ2UiOjI1LCJleHAiOjE3NDQxMjAxNzUsImlhdCI6MTc0NDEyMDE3NCwiaXNzIjoiYmxhY2tkdSIsIm5hbWUiOiJhbmtpdCJ9.W6OQHMRdcRiPS398p8u0vLjpq34oxYPDengillXSFEDXJVXOkzl0ncCpju0yuMOhrQLRRG0EJLKfoFcAxsbpDA" payload, err := Sign(privKey, map[string]any{"name": "ankit", "age": 25}, "blackdu", time.Second) if err != nil { t.Fatal(err) } claims, err := Parse(privKey, payload, "blackdu") if err != nil { t.Fatal(err) } fmt.Printf("%v", claims) } func TestHS256(t *testing.T) { secret := []byte("c4c5fcb25e289e7a23763b013f04fd11b6b0247729216bb98d07f58332360aec") claims := map[string]any{ "id": 1, "email": "aa@aa.com", } issuer := "pat" // Sign jwt, err := SignHS256(secret, claims, issuer, time.Second) if err != nil { t.Error(err) return } t.Log("jwt", jwt) // Parse _, err = ParseHS256(secret, jwt, issuer) if err != nil { t.Error(err) return } } func TestES256(t *testing.T) { // Generate ECDSA P-256 key pair for testing privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } claims := map[string]any{ "email": "user@example.com", } issuer := "https://appleid.apple.com" audience := "com.example.app" subject := "001234.56789abcdef.1234" // Sign with issuer, audience, and subject token, err := SignES256(privKey, issuer, audience, subject, time.Hour, claims) if err != nil { t.Fatal(err) } t.Log("ES256 token:", token) // Parse with issuer and audience validation parsedClaims, err := ParseES256(&privKey.PublicKey, token, issuer, audience) if err != nil { t.Fatal(err) } // Verify claims if parsedClaims["sub"] != subject { t.Errorf("expected sub to be '%s', got %v", subject, parsedClaims["sub"]) } if parsedClaims["aud"] != audience { t.Errorf("expected aud to be '%s', got %v", audience, parsedClaims["aud"]) } if parsedClaims["email"] != "user@example.com" { t.Errorf("expected email to be 'user@example.com', got %v", parsedClaims["email"]) } t.Logf("Parsed claims: %v", parsedClaims) // Test parsing without validation (empty strings) parsedClaims2, err := ParseES256(&privKey.PublicKey, token, "", "") if err != nil { t.Fatal(err) } if parsedClaims2["sub"] != subject { t.Errorf("expected sub to be '%s', got %v", subject, parsedClaims2["sub"]) } } func TestES256_ExpiredToken(t *testing.T) { // Generate ECDSA P-256 key pair for testing privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } claims := map[string]any{} issuer := "https://appleid.apple.com" subject := "001234.56789abcdef.1234" // Sign with very short duration token, err := SignES256(privKey, issuer, "", subject, time.Nanosecond, claims) if err != nil { t.Fatal(err) } // Wait for token to expire time.Sleep(10 * time.Millisecond) // Parse should fail due to expiration _, err = ParseES256(&privKey.PublicKey, token, issuer, "") if err == nil { t.Error("expected error for expired token, got nil") } t.Logf("Expected error for expired token: %v", err) } func TestES256_InvalidIssuer(t *testing.T) { // Generate ECDSA P-256 key pair for testing privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } claims := map[string]any{} issuer := "https://appleid.apple.com" subject := "001234.56789abcdef.1234" // Sign with one issuer token, err := SignES256(privKey, issuer, "", subject, time.Hour, claims) if err != nil { t.Fatal(err) } // Parse with different issuer should fail _, err = ParseES256(&privKey.PublicKey, token, "https://wrong-issuer.com", "") if err == nil { t.Error("expected error for invalid issuer, got nil") } t.Logf("Expected error for invalid issuer: %v", err) } func TestES256_InvalidAudience(t *testing.T) { // Generate ECDSA P-256 key pair for testing privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } claims := map[string]any{} issuer := "https://appleid.apple.com" audience := "com.example.app" subject := "001234.56789abcdef.1234" // Sign with one audience token, err := SignES256(privKey, issuer, audience, subject, time.Hour, claims) if err != nil { t.Fatal(err) } // Parse with different audience should fail _, err = ParseES256(&privKey.PublicKey, token, issuer, "com.wrong.app") if err == nil { t.Error("expected error for invalid audience, got nil") } t.Logf("Expected error for invalid audience: %v", err) }