Skip to content

Make Git tokens reusable for API and MCP with configurable expiration - #8

Merged
hekuo5310 merged 1 commit into
mainfrom
feat/personal-api-tokens
Oct 5, 2026
Merged

hekuo5310 merged 1 commit into
mainfrom
feat/personal-api-tokens

Conversation

@hekuo5310

Copy link
Copy Markdown
Member

Git credentials were limited to Git with a fixed 30-day lifetime. Personal API tokens now work as Git passwords and Bearer credentials for Wiki APIs and MCP. Users can select 7/30/90/365 days, a custom expiration, or no expiration from Git editing or the new /tokens page linked in personal settings.

Existing git_ tokens and /api/me/git-token remain compatible; new tokens use wiki_ and /api/me/api-token. Storage remains hashed and rotation replaces the previous token. Every request checks the current account, permissions, ban status and expiration. Only authenticated Bearer requests bypass browser CSRF and interactive Turnstile checks; token management requires a browser session. Account deletion revokes personal credentials. Git non-fast-forward rejection remains intact.

Validation: server/client typechecks, real Git transport tests, eight service tests covering Worker API and MCP authentication, API writes, expiration, rotation, revocation, bans, compatibility, cookie CSRF and management isolation; full build and all 42 localized shells pass. Policy templates and documentation updated.

@hekuo5310
hekuo5310 merged commit a9f0877 into main Oct 5, 2026
1 check passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b897abb08c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/middleware/session.ts
Comment on lines +33 to +37
if (c.req.path.startsWith('/api/') && /^Bearer (?:wiki|git)_/i.test(authorization)) {
const user = await authenticatePersonalToken(c.env, authorization.slice(7).trim());
if (!user) return c.json({ error: 'Invalid or expired API token' }, 401, { 'Cache-Control': 'no-store' });
c.set('user', user); c.set('apiTokenAuthenticated', true);
return next();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Prevent API tokens from minting browser sessions via QR login

Because this authenticates personal tokens for every /api/* route, a token holder can call /api/qr-login/start, approve that request through /api/qr-login/approve using the bearer token, and redeem the secret for a six-hour browser session cookie. That cookie then passes requireBrowserSession, allowing the holder to rotate/revoke personal tokens or MCP keys despite the intended browser-session-only boundary, and a stolen token can therefore be converted into persistent account access. Exclude the QR approval flow from bearer authentication or explicitly require a browser session there.

Useful? React with 👍 / 👎.

Comment thread src/middleware/session.ts
const authorization = c.req.header('Authorization') || '';
if (c.req.path.startsWith('/api/') && /^Bearer (?:wiki|git)_/i.test(authorization)) {
const user = await authenticatePersonalToken(c.env, authorization.slice(7).trim());
if (!user) return c.json({ error: 'Invalid or expired API token' }, 401, { 'Cache-Control': 'no-store' });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Let MCP return its bearer authentication challenge

When an expired, revoked, or malformed wiki_/git_ token is sent to /api/mcp, this early response prevents resolveBearerAuth from handling it. The MCP-specific handler deliberately returns a WWW-Authenticate header containing the protected-resource metadata so clients can initiate reauthentication, whereas this response has no challenge header; clients using a personal token will therefore stop with a generic 401 when it expires instead of entering the MCP authentication flow. Skip personal-token session handling for /api/mcp and let its existing bearer resolver validate these tokens.

Useful? React with 👍 / 👎.

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