Conversation
appleboy
commented
Feb 23, 2026
- Add OIDC Discovery and UserInfo endpoints for OpenID Connect support
- Register new public routes for OIDC metadata and user profile claims in the router
- Implement a handler for returning OIDC provider metadata and user claims based on granted scopes
- Include comprehensive tests for OIDC handler logic and edge cases
- Update documentation and architecture descriptions to cover OIDC features and endpoints
- Expand referenced standards to include RFC 8414 and OpenID Connect Core specifications
- Add OIDC Discovery and UserInfo endpoints for OpenID Connect support - Register new public routes for OIDC metadata and user profile claims in the router - Implement a handler for returning OIDC provider metadata and user claims based on granted scopes - Include comprehensive tests for OIDC handler logic and edge cases - Update documentation and architecture descriptions to cover OIDC features and endpoints - Expand referenced standards to include RFC 8414 and OpenID Connect Core specifications Signed-off-by: appleboy <appleboy.tw@gmail.com>
There was a problem hiding this comment.
Pull request overview
This pull request adds OpenID Connect (OIDC) Discovery and UserInfo endpoint support to the AuthGate OAuth 2.0 server, enabling standard OIDC client integration.
Changes:
- Implements OIDC Discovery endpoint (
/.well-known/openid-configuration) returning provider metadata per RFC 8414 - Implements UserInfo endpoint (
/oauth/userinfo) that returns user profile claims based on granted scopes (OIDC Core 1.0 §5.3) - Adds comprehensive tests for helper functions and HTTP handlers covering various scope combinations and error cases
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/handlers/oidc.go | New OIDC handler implementing Discovery and UserInfo endpoints with scope-based claim filtering |
| internal/handlers/oidc_test.go | Comprehensive unit tests for helper functions and HTTP handler error cases |
| internal/bootstrap/router.go | Registers OIDC Discovery (public) and UserInfo (GET/POST) routes |
| internal/bootstrap/handlers.go | Initializes OIDCHandler with required service dependencies |
| docs/ARCHITECTURE.md | Documents new OIDC endpoints, claims mapping, and example responses |
| README.md | Updates feature list and endpoint table to include OIDC support with RFC references |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }, | ||
| ClaimsSupported: []string{ | ||
| "sub", | ||
| "iss", |
There was a problem hiding this comment.
The Discovery endpoint advertises "iss" in ClaimsSupported but the buildUserInfoClaims function does not include this claim in the UserInfo response. According to OIDC Core 1.0 section 5.3.2, while the "iss" claim is optional in UserInfo responses, if it's advertised as supported, it should be included. Consider either removing "iss" from ClaimsSupported in the Discovery metadata or adding it to the claims map in buildUserInfoClaims (the issuer value can be obtained from h.config.BaseURL).
| "iss", |
| "iss", | ||
| "name", | ||
| "preferred_username", | ||
| "email", |
There was a problem hiding this comment.
The buildUserInfoClaims function returns the "email_verified" claim when the email scope is granted, but this claim is not listed in the ClaimsSupported array in the Discovery metadata. According to OIDC Core 1.0, if a claim is returned by the UserInfo endpoint, it should be advertised in the claims_supported field. Consider adding "email_verified" to the ClaimsSupported array to maintain consistency between what's advertised and what's actually returned.
| "email", | |
| "email", | |
| "email_verified", |
| var body map[string]any | ||
| require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body)) | ||
| assert.Equal(t, "invalid_token", body["error"]) | ||
| } |
There was a problem hiding this comment.
Missing test coverage for UserInfo endpoint success path. The tests cover error cases (no auth header, non-Bearer token) but lack a positive test case where a valid Bearer token is provided, the token is successfully validated, the user is found, and claims are returned. Consider adding a test that mocks or stubs the TokenService.ValidateToken and UserService.GetUserByID methods to verify the happy path, ensuring the endpoint correctly returns user claims with HTTP 200 status.
| } | |
| } | |
| // mockTokenService is a minimal stub that simulates successful token validation. | |
| type mockTokenService struct{} | |
| func (m *mockTokenService) ValidateToken(rawToken string) (string, error) { | |
| // In a real implementation this would validate the token and return a user ID. | |
| // For this test, always return a fixed user ID to drive the happy path. | |
| return "user-123", nil | |
| } | |
| // mockUserService is a minimal stub that simulates loading a user and returning claims. | |
| type mockUserService struct{} | |
| func (m *mockUserService) GetUserByID(userID string) (map[string]any, error) { | |
| // For the purposes of this test, return a simple claim set. | |
| return map[string]any{ | |
| "sub": userID, | |
| "email": "user@example.com", | |
| "name": "Test User", | |
| }, nil | |
| } | |
| // ============================================================ | |
| // OIDCHandler.UserInfo – valid Bearer token (happy path) | |
| // ============================================================ | |
| func TestUserInfo_ValidBearerToken_Returns200WithClaims(t *testing.T) { | |
| gin.SetMode(gin.TestMode) | |
| cfg := &config.Config{BaseURL: "https://auth.example.com"} | |
| tokenSvc := &mockTokenService{} | |
| userSvc := &mockUserService{} | |
| handler := NewOIDCHandler(tokenSvc, userSvc, cfg) | |
| r := gin.New() | |
| r.GET("/oauth/userinfo", handler.UserInfo) | |
| req := httptest.NewRequest(http.MethodGet, "/oauth/userinfo", nil) | |
| req.Header.Set("Authorization", "Bearer valid-access-token") | |
| w := httptest.NewRecorder() | |
| r.ServeHTTP(w, req) | |
| require.Equal(t, http.StatusOK, w.Code) | |
| var body map[string]any | |
| require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body)) | |
| // Verify that some key claims are present in the response. | |
| assert.Equal(t, "user-123", body["sub"]) | |
| assert.Equal(t, "user@example.com", body["email"]) | |
| assert.Equal(t, "Test User", body["name"]) | |
| } |
- Add "email_verified" to the supported claims in OIDC discovery metadata
- Include the issuer ("iss") claim in user info responses
- Update documentation and tests to reflect that both "sub" and "iss" are always present
- Extend tests to verify the presence of the "iss" claim in user info and discovery responses
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>