Repository navigation
Description
Problem
GitHub OAuth is not standard OIDC — it lacks .well-known/openid-configuration discovery, issues opaque access tokens (not JWTs), never returns an id_token, and uses non-standard user API claims (id/login instead of sub, no email_verified). The current OAuth implementation nearly supports GitHub via the fetchUserInfo fallback path, but four gaps prevent it from working end-to-end.
Why GitHub?
GitHub is one of the most widely used identity providers for developer tooling. Supporting it broadens the MCP server's audience, especially for teams already using GitHub for authentication across their infrastructure.
What doesn't work today
| Gap | Detail |
|---|---|
| Claim mapping | GitHub's /user returns id (int) and login instead of OIDC-standard sub. oauthClaimsFromUserInfo produces an empty Subject. |
| Email verification | GitHub's /user endpoint has no email_verified field. require_email_verified: true rejects all GitHub users. Verified email status requires a separate GET /user/emails call. |
| Private emails | GitHub may return email: null when the user's email is private — again requiring /user/emails. |
| Accept headers | Some GitHub API endpoints benefit from explicit Accept: application/json headers. |
Proposed approach: generic enhancements (no GitHub-specific code)
All changes are provider-agnostic — no if provider == "github" anywhere. This benefits any future non-OIDC OAuth2 provider (Bitbucket, GitLab self-hosted, custom APIs).
1. New config fields in OAuthConfig (pkg/config/config.go)
| Field | Type | Purpose |
|---|---|---|
userinfo_claims_mapping |
map[string]string |
Maps upstream fields to standard OIDC claims (e.g., {"id": "sub", "login": "preferred_username"}) |
userinfo_email_url |
string |
Secondary endpoint for verified email (e.g., https://api.github.com/user/emails) |
userinfo_accept_header |
string |
Accept header for userinfo requests |
token_request_accept_header |
string |
Accept header for token exchange requests |
2. Claim mapping in oauthClaimsFromUserInfo (cmd/altinity-mcp/oauth_server.go)
- Add
claimsMapping map[string]stringparameter - Before extracting standard fields, apply mapping: copy
raw[srcKey]→raw[dstKey]if target not already set - Handle numeric
id(float64) → string conversion forsubfield
3. New helper: fetchVerifiedEmail
GETtouserinfo_email_urlwithAuthorization: Bearer {token}- Parses JSON array of
{email, primary, verified}objects (GitHub's/user/emailsformat) - Returns first
primary=true && verified=trueemail
4. Enhance fetchUserInfo
- Add
Acceptheader whenuserinfo_accept_headeris configured - Pass
userinfo_claims_mappingto claim extraction - After claim extraction, if email missing/unverified and
userinfo_email_urlconfigured, callfetchVerifiedEmail
5. Token exchange Accept header (handleOAuthCallback)
- Replace
PostFormwith manualhttp.NewRequestto support configurableAcceptheader
GitHub config example
server:
oauth:
enabled: true
mode: "gating"
gating_secret_key: "<RANDOM_SECRET>"
issuer: "https://github.com"
client_id: "<GITHUB_CLIENT_ID>"
client_secret: "<GITHUB_CLIENT_SECRET>"
auth_url: "https://github.com/login/oauth/authorize"
token_url: "https://github.com/login/oauth/access_token"
userinfo_url: "https://api.github.com/user"
userinfo_email_url: "https://api.github.com/user/emails"
userinfo_accept_header: "application/json"
token_request_accept_header: "application/json"
scopes: ["user:email"]
userinfo_claims_mapping:
id: "sub"
login: "preferred_username"
require_email_verified: trueNote: Gating mode is required because GitHub issues opaque tokens that ClickHouse cannot validate directly.
Files to modify
pkg/config/config.go— Add 4 new OAuthConfig fieldscmd/altinity-mcp/oauth_server.go— Core logic (claim mapping, email fetch, Accept headers)cmd/altinity-mcp/oauth_server_test.go— Unit + integration testsdocs/oauth_authorization.md— GitHub provider docs + general non-OIDC sectionhelm/altinity-mcp/values_examples/mcp-oauth-github.yaml— New Helm example
Test plan
- Unit: claim mapping with/without config, numeric ID conversion, mapping doesn't overwrite existing fields, email fetch success/failure
- Integration: mock GitHub-like upstream (opaque token,
/userwithid/login,/user/emailswith verified array) — full callback flow - Regression: all existing OAuth tests pass unchanged (nil mapping = backward compatible)
Activity
Add GitHub as OAuth identity provider via generic non-OIDC support
Add GitHub as OAuth identity provider via generic non-OIDC support
Add GitHub as OAuth identity provider via generic non-OIDC support