feat(github): synthetic OAuth refresh flow for MINT_REPO_TOKEN#449
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ping Implements Task 7: redeems a synthetic refresh token for a fresh ghs_ token using only GitHub App credentials. Maps 422/404 → 400 invalid_grant (grant deleted) and 401/403/5xx/JWT-config/storage errors → 503 temporarily_unavailable (grant kept). Includes sliding TTL on success. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…map; add 404/omitted-client_id tests
Implements revokeRepoGrant (RFC 7009: always 200, 503 on storage failure), handleRepoGrantTokenRequest, handleRepoGrantRevokeRequest, and helper exports repoGrantBaseUrl/repoGrantClientId. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the thin mintRepoScopedToken adapter with mintRepoTokenWithGrant, exposing refreshToken, tokenEndpoint, clientId, refreshTokenExpiresAt, expiresIn, tokenType, and repository.id in the tool response. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire REPO_GRANTS KV binding into handle() via setRepoGrantKV(), route POST /repo-grant/token and POST /repo-grant/revoke to their HTTP adapters before the MCP proxy, add a one-time warn if the binding is missing, and register the REPO_GRANTS kv_namespaces entry in wrangler.toml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
MINT_REPO_TOKENnow mints the short-livedghs_token and issues a durable, revocable synthetic refresh token (ghr_<grantId>.<secret>, an MCP-issued repo grant — not a GitHub refresh token), returningrefreshToken/tokenEndpoint/clientIdwhile keeping all legacy output fields. Two new unauthenticated endpoints —POST /repo-grant/token(re-mints a repo-scoped token via a GitHub App JWT; permanent400 invalid_grantvs transient503so the mesh never discards a valid grant) andPOST /repo-grant/revoke(RFC 7009) — redeem/revoke grants using only App credentials, with no user-to-server token at refresh time. Grants persist in a newREPO_GRANTSCloudflare KV namespace storing onlysha256(secret)(constant-time verified) with a sliding 90-day TTL, namespaced under/repo-grant/*to avoid the runtime's/oauth/*routes. The change is fully backward compatible and covered by 86 passing tests with a clean typecheck and dry-run build.cd github && bunx wrangler kv namespace create REPO_GRANTS) and replace the placeholder id inwrangler.toml, or the post-mergewrangler deploywill fail.🤖 Generated with Claude Code
Summary by cubic
Adds a synthetic OAuth-style refresh flow to
MINT_REPO_TOKEN. We still mint the short-lived GitHubghs_token, and now also return a durable, revocable repo grant (ghr_<grantId>.<secret>) with atokenEndpointandclientIdso refresh needs only the GitHub App, not a user token.New Features
MINT_REPO_TOKENnow returnsrefreshToken,tokenEndpoint,clientId,refreshTokenExpiresAt,expiresIn,tokenType, andrepository.id(keeps all legacy fields).POST /repo-grant/token(redeemsrefresh_token) andPOST /repo-grant/revoke(RFC 7009). Unauthenticated, size-limited, and map GitHub 422/404 →400 invalid_grantand 401/5xx →503 temporarily_unavailable.REPO_GRANTSKV with SHA-256 secret hashing, constant-time verify, and a sliding 90-day TTL.PUBLIC_BASE_URLsets the absolutetokenEndpoint.mintRepoScopedTokenaccepts optionalrepositoryId, cross-checks it, and returnsrepositoryId.Migration
bunx wrangler kv namespace create REPO_GRANTS, then replace the placeholder id inwrangler.toml.PUBLIC_BASE_URLto your public origin; defaults tohttps://github-mcp.decocms.com.Written for commit 4770d2e. Summary will update on new commits.