Skip to content

Comments

Multi-IDP support #33

Merged
dgellow merged 7 commits intomainfrom
claude/review-issues-31-29-01Muf22zzg1npTgA3sB9MDup
Feb 12, 2026
Merged

Multi-IDP support #33
dgellow merged 7 commits intomainfrom
claude/review-issues-31-29-01Muf22zzg1npTgA3sB9MDup

Conversation

@dgellow
Copy link
Member

@dgellow dgellow commented Nov 30, 2025

Summary

  • Replace Google-specific OAuth with a provider abstraction supporting Google, Azure AD, GitHub, and generic OIDC
  • Separate authentication (identity fetching) from authorization (access policy) so IDP errors and policy rejections produce distinct error types
  • Systematic quality pass: fix bugs, unify patterns, reduce complexity

Breaking change

Config format changes from flat googleClientId/googleClientSecret fields to a structured idp block:

"idp": {
  "provider": "google|azure|github|oidc",
  "clientId": "...",
  "clientSecret": {"$env": "..."},
  "redirectUri": "..."
}

Quality improvements

  • Fix duplicate isStdioServer with diverging implementations
  • Unify CSRF tokens to stateless HMAC approach (removes sync.Map leak)
  • Make StoreAuthorizeRequest return error (Firestore failures were silent)
  • Fix SameSite cookie mismatch (Strict → Lax for OAuth callbacks)
  • Add GetUser to Storage interface for O(1) admin checks
  • Split oversized files, consolidate tiny packages, delete dead code

Closes #31, closes #29

@dgellow dgellow marked this pull request as draft November 30, 2025 13:39
@dgellow dgellow force-pushed the claude/review-issues-31-29-01Muf22zzg1npTgA3sB9MDup branch from 0e55db2 to 60d70d0 Compare November 30, 2025 13:39
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @dgellow, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the authentication system by introducing a robust Identity Provider (IDP) abstraction. This change moves away from a hardcoded Google OAuth implementation to a flexible, pluggable model that can integrate with various IDPs like Google, Azure AD, GitHub, and any OIDC-compliant service. The update involves substantial changes to configuration, validation, and core authentication handlers to support this new multi-IDP architecture, enhancing the system's extensibility and security.

Highlights

  • Multi-IDP Support: The system now supports multiple Identity Providers (IDPs) including Google, Azure AD, GitHub, and generic OIDC providers, replacing the previous Google-specific OAuth implementation.
  • Provider Abstraction Layer: A new internal/idp package has been introduced, defining a Provider interface and concrete implementations for each supported IDP, centralizing authentication logic.
  • Configuration Changes: The OAuth configuration format has been updated to include a nested idp block, which encapsulates provider-specific settings like provider type, clientId, clientSecret, and redirectUri.
  • Enhanced Validation: Validation logic has been extended to enforce required fields for the new idp configuration and to include provider-specific requirements, such as tenantId for Azure AD and allowedOrgs for GitHub.
  • Session Cookie Update: The SessionCookie struct now includes a Provider field to track which Identity Provider authenticated the user, enabling multi-IDP session management.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is an excellent refactoring effort that replaces a Google-specific OAuth implementation with a flexible, provider-based abstraction. The introduction of the internal/idp package with a Provider interface is well-executed and allows for easy extension to other identity providers. The configuration changes, while breaking, are clearly documented and the new structure is more logical. The validation logic has been updated to be provider-aware, which is a great improvement. I've identified a couple of areas for improvement, mainly around code duplication in the configuration parsing and test coverage for the new GitHub provider. Overall, this is a high-quality change that significantly improves the authentication capabilities of the application.

@dgellow dgellow force-pushed the claude/review-issues-31-29-01Muf22zzg1npTgA3sB9MDup branch 4 times, most recently from b4851d1 to c580b4e Compare December 2, 2025 00:22
dgellow and others added 2 commits February 12, 2026 09:20
Replaces Google-specific OAuth with a provider abstraction pattern
supporting Google, Azure AD, GitHub, and generic OIDC providers.

Changes:
- Create internal/idp package with Provider interface and implementations
- Update config from googleClientId/googleClientSecret to structured idp block
- Add provider tracking to browser session cookies for multi-IDP readiness
- Delete internal/googleauth package
- Add comprehensive tests for idp package (including GitHub UserInfo tests)
- Update all example configs and documentation
- Refactor parseIDPConfig to use helper function for cleaner code

Config format change:
  "idp": {
    "provider": "google|azure|github|oidc",
    "clientId": "...",
    "clientSecret": {"$env": "..."},
    "redirectUri": "...",
    // Provider-specific: tenantId (azure), allowedOrgs (github), discoveryUrl (oidc)
  }

Co-authored-by: Claude <noreply@anthropic.com>
Previously allowedDomains was passed at call time to UserInfo(), while
allowedOrgs was configured at construction. This inconsistency made the
interface harder to understand and didn't follow the principle that
access control should be configured when the provider is created.

Changes:
- Provider.UserInfo() now takes only context and token
- All providers store allowedDomains internally
- Factory accepts allowedDomains parameter
- All tests updated to reflect new interface
@dgellow dgellow force-pushed the claude/review-issues-31-29-01Muf22zzg1npTgA3sB9MDup branch from f092c4d to 9ccd1ff Compare February 12, 2026 08:20
Providers now only fetch identity — access control (domain/org checks)
is centralized in a single validateAccess method on the auth handler.
This means IDP errors (unreachable provider) produce ErrServerError
while policy rejections produce ErrAccessDenied, and adding new access
rules no longer requires touching every provider.

GitHub always fetches orgs now (scope was already requested
unconditionally). UserInfo struct renamed to Identity to avoid collision
with the method name. ParseClientRequest relocated to oauth package as
ParseClientRegistration. Deleted deprecated ProtectedResourceMetadata
and inlined the workaround logic into the handler that used it.
Fix duplicate isStdioServer with diverging implementations by adding
IsStdio() method on MCPClientConfig. Unify CSRF strategy across admin
and token handlers using stateless HMAC-based tokens (removes sync.Map
approach). Make StoreAuthorizeRequest return an error so Firestore
failures surface clearly. Use cookie.SetSession consistently (fixes
SameSite mismatch from Strict to Lax for OAuth callbacks).

Split http.go into focused files (user_token_service.go,
session_handler.go). Extract handleBrowserCallback and
handleOAuthClientCallback from 190-line IDPCallbackHandler. Add
GetUser to Storage interface for O(1) admin checks. Consolidate
browserauth + oauthsession into internal/session, move envutil.IsDev
into config package. Replace hardcoded Firestore collection names
with constants. Delete unused GetErrorName. Update CLAUDE.md to
reference ./scripts/ instead of make.
@dgellow dgellow changed the title Implement multi-IDP support with provider abstraction Multi-IDP support and codebase quality pass Feb 12, 2026
@dgellow dgellow marked this pull request as ready for review February 12, 2026 09:40
@dgellow
Copy link
Member Author

dgellow commented Feb 12, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an excellent pull request that significantly improves the authentication architecture by introducing a well-designed abstraction for multiple identity providers. The separation of authentication (identity fetching) from authorization (access policy) is a great design choice that enhances clarity and flexibility. The codebase quality pass has resulted in numerous improvements, such as fixing the stateful CSRF implementation, improving database lookups for admin checks, and general code cleanup by splitting oversized files and consolidating small packages. The changes are consistently applied across the configuration, implementation, tests, and documentation. I have one minor suggestion to improve the clarity of a validation error message.

Comment on lines 201 to 203
if len(oauth.JWTSecret) < 32 {
return fmt.Errorf("jwtSecret must be at least 32 characters (got %d). Generate with: openssl rand -base64 32", len(oauth.JWTSecret))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The suggested command openssl rand -base64 32 generates a 44-character string, which might be confusing given the 32-character minimum requirement. To avoid this confusion and provide a command that generates a key closer to the minimum length, you could suggest openssl rand -base64 24 which produces exactly 32 characters.

Suggested change
if len(oauth.JWTSecret) < 32 {
return fmt.Errorf("jwtSecret must be at least 32 characters (got %d). Generate with: openssl rand -base64 32", len(oauth.JWTSecret))
}
if len(oauth.JWTSecret) < 32 {
return fmt.Errorf("jwtSecret must be at least 32 characters (got %d). Generate with: openssl rand -base64 24", len(oauth.JWTSecret))
}

Replace the removed mcp/postgres Docker image with Google's MCP Toolbox
for Databases. Convert 8 static JSON test configs to programmatic
generation via Go builder functions so the image reference lives in one
place (ToolboxImage constant).

Key changes:
- GoogleProvider now accepts optional endpoint overrides for
  authorizationUrl, tokenUrl, and userInfoUrl, replacing the broken
  GOOGLE_OAUTH_* env vars that were never actually read
- Integration tests use execute_sql tool instead of query (toolbox API)
- Remove dead code: TestEnvironment, SetupTestEnvironment,
  execDockerCompose helpers
- Pull toolbox image in TestMain to prevent first-test timeout
- Update all example configs and --config-init default
Add endpoint overrides to GitHub and Azure providers so they can point
at local fake servers during testing, matching the existing Google
provider pattern. Create FakeGitHubServer (port 9092) and FakeOIDCServer
(port 9093) alongside FakeGCPServer to simulate all four supported IDPs.

New integration tests exercise the full OAuth flow for GitHub, OIDC, and
Azure providers end-to-end (register client → authorize → IDP redirect →
callback → token exchange → MCP tools/list). Also tests org denial for
GitHub and domain denial across all three providers.

Reorganize integration directory: split test_utils.go (993 lines) into
test_helpers.go, test_clients.go, test_fakes.go. Split oauth_test.go
(1576 lines) into oauth_flow_test.go, oauth_user_tokens_test.go,
oauth_service_test.go, oauth_rfc8707_test.go, oauth_idp_test.go.
@dgellow dgellow changed the title Multi-IDP support and codebase quality pass Multi-IDP support Feb 12, 2026
@dgellow dgellow enabled auto-merge (squash) February 12, 2026 22:10
@dgellow dgellow disabled auto-merge February 12, 2026 22:10
@dgellow dgellow enabled auto-merge (squash) February 12, 2026 22:10
@dgellow dgellow disabled auto-merge February 12, 2026 22:12
@dgellow dgellow merged commit 22a60d7 into main Feb 12, 2026
2 checks passed
@dgellow dgellow deleted the claude/review-issues-31-29-01Muf22zzg1npTgA3sB9MDup branch February 12, 2026 22:20
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.

Bring your own IDP Interest in supporting additional OAuth providers?

2 participants