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]string parameter
- Before extracting standard fields, apply mapping: copy
raw[srcKey] → raw[dstKey] if target not already set
- Handle numeric
id (float64) → string conversion for sub field
3. New helper: fetchVerifiedEmail
GET to userinfo_email_url with Authorization: Bearer {token}
- Parses JSON array of
{email, primary, verified} objects (GitHub's /user/emails format)
- Returns first
primary=true && verified=true email
4. Enhance fetchUserInfo
- Add
Accept header when userinfo_accept_header is configured
- Pass
userinfo_claims_mapping to claim extraction
- After claim extraction, if email missing/unverified and
userinfo_email_url configured, call fetchVerifiedEmail
5. Token exchange Accept header (handleOAuthCallback)
- Replace
PostForm with manual http.NewRequest to support configurable Accept header
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: true
Note: 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 fields
cmd/altinity-mcp/oauth_server.go — Core logic (claim mapping, email fetch, Accept headers)
cmd/altinity-mcp/oauth_server_test.go — Unit + integration tests
docs/oauth_authorization.md — GitHub provider docs + general non-OIDC section
helm/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,
/user with id/login, /user/emails with verified array) — full callback flow
- Regression: all existing OAuth tests pass unchanged (nil mapping = backward compatible)
Problem
GitHub OAuth is not standard OIDC — it lacks
.well-known/openid-configurationdiscovery, issues opaque access tokens (not JWTs), never returns anid_token, and uses non-standard user API claims (id/logininstead ofsub, noemail_verified). The current OAuth implementation nearly supports GitHub via thefetchUserInfofallback 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
/userreturnsid(int) andlogininstead of OIDC-standardsub.oauthClaimsFromUserInfoproduces an emptySubject./userendpoint has noemail_verifiedfield.require_email_verified: truerejects all GitHub users. Verified email status requires a separateGET /user/emailscall.email: nullwhen the user's email is private — again requiring/user/emails.Accept: application/jsonheaders.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)userinfo_claims_mappingmap[string]string{"id": "sub", "login": "preferred_username"})userinfo_email_urlstringhttps://api.github.com/user/emails)userinfo_accept_headerstringtoken_request_accept_headerstring2. Claim mapping in
oauthClaimsFromUserInfo(cmd/altinity-mcp/oauth_server.go)claimsMapping map[string]stringparameterraw[srcKey]→raw[dstKey]if target not already setid(float64) → string conversion forsubfield3. New helper:
fetchVerifiedEmailGETtouserinfo_email_urlwithAuthorization: Bearer {token}{email, primary, verified}objects (GitHub's/user/emailsformat)primary=true && verified=trueemail4. Enhance
fetchUserInfoAcceptheader whenuserinfo_accept_headeris configureduserinfo_claims_mappingto claim extractionuserinfo_email_urlconfigured, callfetchVerifiedEmail5. Token exchange Accept header (
handleOAuthCallback)PostFormwith manualhttp.NewRequestto support configurableAcceptheaderGitHub config example
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 exampleTest plan
/userwithid/login,/user/emailswith verified array) — full callback flow