package oidc import ( "context" "testing" "time" "gitea.dcglab.co.uk/steve/restic-manager/internal/server/config" "gitea.dcglab.co.uk/steve/restic-manager/internal/server/oidc/oidctest" ) func TestClientExchangeAgainstStub(t *testing.T) { t.Parallel() stub := oidctest.New(t) cfg := &config.OIDCConfig{ Issuer: stub.URL(), ClientID: "test-client", ClientSecret: "x", Scopes: []string{"openid"}, RoleClaim: "groups", RoleMapping: map[string]string{"rm-admins": "admin"}, } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() c, err := New(ctx, cfg, "http://rm.example") if err != nil { t.Fatalf("new client: %v", err) } code := stub.MintCode(map[string]any{ "sub": "abc", "preferred_username": "alice", "email": "alice@example.com", "groups": []string{"rm-admins"}, }) verifier, _, err := PKCEPair() if err != nil { t.Fatalf("pkce: %v", err) } claims, raw, err := c.Exchange(ctx, code, verifier) if err != nil { t.Fatalf("exchange: %v", err) } if claims.Subject != "abc" || claims.PreferredUsername != "alice" { t.Errorf("claims: %+v", claims) } if c.MapRole(claims.Roles) != "admin" { t.Errorf("role: got %q", c.MapRole(claims.Roles)) } if raw == "" { t.Error("raw id_token must be non-empty") } }