You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sub-issue of #86. Wires MCP token lifecycle events into Harper's audit channel and adds a lifecycle hook so app authors can react to token issuance (rate limiting, billing, custom logging, etc.).
Context
By the time Stage 5 lands, Harper apps using @harperfast/oauth can serve a full MCP OAuth flow — but there's no audit trail beyond ad-hoc logger calls, and apps can't hook into the token-issuance moment the way they can hook into human OAuth (onLogin). This stage closes both gaps with one PR.
What this adds
Three audit event types emitted via Harper's existing audit channel (same one used by human-OAuth events):
oauth.mcp.token.issued — when /oauth/mcp/token mints a new access token
oauth.mcp.token.refreshed — when /oauth/mcp/token rotates a refresh token
oauth.mcp.token.rejected — when token validation fails in withMCPAuth (any of the rejection branches from Stage 5)
onMCPTokenIssued lifecycle hook added to the existing OAuthHooks interface in src/types.ts. Signature:
Fired from /oauth/mcp/token after the JWT is signed and before the response is sent. App-author use case: rate limit by client_id, attribute usage for billing, push to a queue, etc.
onLogin already fires from the bridged authorize flow (Stage 3) — verify and document that the existing hook works unchanged for MCP-initiated auth; add a test that asserts it.
Spec requirements
No spec MUST/SHOULD here — auditing is a Harper-side concern, not an MCP spec mandate. The MCP authorization spec 2025-06-18 doesn't say anything about audit logging.
Acceptance
oauth.mcp.token.issued, oauth.mcp.token.refreshed, oauth.mcp.token.rejected events emit on the corresponding paths (Stages 4 and 5)
Event payloads include client_id, sub, aud, scope, jti, and a timestamp — no token material (never log tokens, per CLAUDE.md)
onMCPTokenIssued hook is added to OAuthHooks interface; fires after JWT mint, before response
onMCPTokenIssued failure in app code is logged but does NOT block token issuance (failure-tolerant)
onLogin hook fires on MCP-initiated auth (regression test against the bridged flow from Stage 3)
Unit tests cover event emission for each of the three event types and the hook fire-and-forget contract
Dependencies
Depends on: Stage 4 (token issuance to instrument), Stage 5 (token validation rejection paths to instrument)
Blocks: none — Stages 7 and 8 don't depend on audit
MCP OAuth Stage 6: audit logging +
onMCPTokenIssuedhookSub-issue of #86. Wires MCP token lifecycle events into Harper's audit channel and adds a lifecycle hook so app authors can react to token issuance (rate limiting, billing, custom logging, etc.).
Context
By the time Stage 5 lands, Harper apps using
@harperfast/oauthcan serve a full MCP OAuth flow — but there's no audit trail beyond ad-hoc logger calls, and apps can't hook into the token-issuance moment the way they can hook into human OAuth (onLogin). This stage closes both gaps with one PR.What this adds
oauth.mcp.token.issued— when/oauth/mcp/tokenmints a new access tokenoauth.mcp.token.refreshed— when/oauth/mcp/tokenrotates a refresh tokenoauth.mcp.token.rejected— when token validation fails inwithMCPAuth(any of the rejection branches from Stage 5)onMCPTokenIssuedlifecycle hook added to the existingOAuthHooksinterface insrc/types.ts. Signature:/oauth/mcp/tokenafter the JWT is signed and before the response is sent. App-author use case: rate limit byclient_id, attribute usage for billing, push to a queue, etc.onLoginalready fires from the bridged authorize flow (Stage 3) — verify and document that the existing hook works unchanged for MCP-initiated auth; add a test that asserts it.Spec requirements
Acceptance
oauth.mcp.token.issued,oauth.mcp.token.refreshed,oauth.mcp.token.rejectedevents emit on the corresponding paths (Stages 4 and 5)client_id,sub,aud,scope,jti, and a timestamp — no token material (never log tokens, per CLAUDE.md)onMCPTokenIssuedhook is added toOAuthHooksinterface; fires after JWT mint, before responseonMCPTokenIssuedfailure in app code is logged but does NOT block token issuance (failure-tolerant)onLoginhook fires on MCP-initiated auth (regression test against the bridged flow from Stage 3)Dependencies
Out of scope
onUpstreamRevoked(v1.1 per Add MCP OAuth flow support #86)🤖 Generated with Claude Code