Skip to content

Comments

feat: add OpenID Connect discovery and userinfo endpoint support#51

Merged
appleboy merged 2 commits intomainfrom
oidc
Feb 24, 2026
Merged

feat: add OpenID Connect discovery and userinfo endpoint support#51
appleboy merged 2 commits intomainfrom
oidc

Conversation

@appleboy
Copy link
Member

  • 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>
Copilot AI review requested due to automatic review settings February 23, 2026 15:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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",
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
"iss",

Copilot uses AI. Check for mistakes.
"iss",
"name",
"preferred_username",
"email",
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
"email",
"email",
"email_verified",

Copilot uses AI. Check for mistakes.
var body map[string]any
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body))
assert.Equal(t, "invalid_token", body["error"])
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
}
}
// 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"])
}

Copilot uses AI. Check for mistakes.
- 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>
@appleboy appleboy merged commit 0f2164b into main Feb 24, 2026
16 checks passed
@appleboy appleboy deleted the oidc branch February 24, 2026 02:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant