package usertoken import ( "crypto/rsa" "encoding/base64" "encoding/json" "errors" "math/big" "net/http" "net/http/httptest" "testing" "time" "github.com/golang-jwt/jwt/v5" ) func TestOIDCVerifier(t *testing.T) { key := testKey(t) var srv *httptest.Server mux := http.NewServeMux() srv = httptest.NewServer(mux) t.Cleanup(srv.Close) mux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { _ = json.NewEncoder(w).Encode(map[string]any{ "issuer": srv.URL, "jwks_uri": srv.URL + "/jwks", "id_token_signing_alg_values_supported": []string{"RS256"}, }) }) mux.HandleFunc("/jwks", func(w http.ResponseWriter, r *http.Request) { _ = json.NewEncoder(w).Encode(publicJWKS(&key.PublicKey)) }) auth, err := New(t.Context(), Config{ OIDCIssuer: srv.URL, OIDCAudience: "mgmnt", GroupsClaim: "identity_groups", }) if err != nil { t.Fatalf("New: %v", err) } now := time.Now() groups := []string{"family"} raw, err := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{ "iss": srv.URL, "sub": "konrad", "preferred_username": "konrad", "aud": "mgmnt", "iat": now.Unix(), "exp": now.Add(time.Minute).Unix(), "identity_groups": groups, }).SignedString(key) if err != nil { t.Fatal(err) } caller, err := auth.Verify(t.Context(), raw) if err != nil { t.Fatalf("Verify: %v", err) } if caller.Subject != "konrad" || len(caller.Groups) != 1 || caller.Groups[0] != "family" { t.Fatalf("caller = %+v", caller) } if _, err := New(t.Context(), Config{ PublicKey: &key.PublicKey, Issuer: "manager", Audience: "mgmnt", OIDCIssuer: srv.URL, }); err == nil { t.Fatal("both modes accepted") } if _, err := auth.Verify(t.Context(), "not-a-token"); !errors.Is(err, ErrUnauthorized) { t.Fatalf("bad token err = %v", err) } } func publicJWKS(pub *rsa.PublicKey) map[string]any { return map[string]any{ "keys": []map[string]string{{ "kty": "RSA", "use": "sig", "alg": "RS256", "n": base64.RawURLEncoding.EncodeToString(pub.N.Bytes()), "e": base64.RawURLEncoding.EncodeToString(big.NewInt(int64(pub.E)).Bytes()), }}, } }