package auth import ( "testing" "time" "github.com/golang-jwt/jwt/v5" ) func TestIssuer_IssueVerify_Roundtrip(t *testing.T) { issuer := NewIssuer([]byte("test-secret-32-bytes-minimum!!!"), time.Hour) token, err := issuer.Issue("user-1", "alice", RoleAdmin, "session-abc") if err != nil { t.Fatalf("Issue: %v", err) } claims, err := issuer.Verify(token) if err != nil { t.Fatalf("Verify: %v", err) } if claims.Subject != "user-1" { t.Errorf("Subject = %q, want %q", claims.Subject, "user-1") } if claims.Username != "alice" { t.Errorf("Username = %q, want %q", claims.Username, "alice") } if claims.Role != RoleAdmin { t.Errorf("Role = %q, want %q", claims.Role, RoleAdmin) } if claims.SessionID != "session-abc" { t.Errorf("SessionID = %q, want %q", claims.SessionID, "session-abc") } } func TestIssuer_Verify_ExpiredToken(t *testing.T) { issuer := NewIssuer([]byte("test-secret-32-bytes-minimum!!!"), -time.Hour) token, err := issuer.Issue("user-1", "alice", RoleClient, "session-abc") if err != nil { t.Fatalf("Issue: %v", err) } if _, err := issuer.Verify(token); err != ErrInvalidToken { t.Errorf("Verify(expired) error = %v, want ErrInvalidToken", err) } } func TestIssuer_Verify_WrongSecret(t *testing.T) { issuer := NewIssuer([]byte("test-secret-32-bytes-minimum!!!"), time.Hour) token, err := issuer.Issue("user-1", "alice", RoleClient, "session-abc") if err != nil { t.Fatalf("Issue: %v", err) } other := NewIssuer([]byte("different-secret-32-bytes-min!!"), time.Hour) if _, err := other.Verify(token); err != ErrInvalidToken { t.Errorf("Verify(wrong secret) error = %v, want ErrInvalidToken", err) } } func TestIssuer_Verify_RejectsNoneAlgorithm(t *testing.T) { issuer := NewIssuer([]byte("test-secret-32-bytes-minimum!!!"), time.Hour) claims := Claims{ Role: RoleAdmin, Username: "attacker", SessionID: "forged", RegisteredClaims: jwt.RegisteredClaims{ Subject: "user-1", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)), }, } forged, err := jwt.NewWithClaims(jwt.SigningMethodNone, claims).SignedString(jwt.UnsafeAllowNoneSignatureType) if err != nil { t.Fatalf("forge none-alg token: %v", err) } if _, err := issuer.Verify(forged); err != ErrInvalidToken { t.Errorf("Verify(none-alg token) error = %v, want ErrInvalidToken (alg-confusion protection)", err) } } func TestIssuer_Verify_MalformedToken(t *testing.T) { issuer := NewIssuer([]byte("test-secret-32-bytes-minimum!!!"), time.Hour) if _, err := issuer.Verify("not.a.token"); err != ErrInvalidToken { t.Errorf("Verify(malformed) error = %v, want ErrInvalidToken", err) } }