Review: Register Notion OAuth app
Verdict: NEEDS_REFINEMENT
Ticket: board item #1046 —
forgejo_admin/notion-mcp-remote#6 — feat: register public Notion OAuth integration for remote proxyLabels:
type:feature, story:claude-ai-connect, arch:notion-oauth — points: 1 — column: backlogTemplate Completeness
Validated against
template-issue-feature:- [x]
### Type— Feature - [x]
### Lineage— standalone, scoped from project - [x]
### Repo—forgejo_admin/notion-mcp-remote - [x]
### User Story— present (AS/I want/So that) - [x]
### Context— clear, explains three-legged flow and Public-vs-Internal distinction - [x]
### File Targets— present (explicitly "no repo file changes") and lists target secrets plus files NOT to touch - [x]
### Acceptance Criteria— 5 ACs, testable - [x]
### Test Expectations— manual browser smoke + curl smoke - [x]
### Constraints— three real constraints listed - [x]
### Checklist— present - [x]
### Related— project + story + arch
Traceability
- [x]
story:claude-ai-connectlabel — Connect Notion to claude.ai - [x] story note verified — entry exists in
project-notion-mcp-remoteuser-stories section, linking tostory-notion-mcp-remote-claude-ai-connect - [x]
arch:notion-oauthlabel — OAuth handshake component - [ ] arch note MISSING under that exact slug —
search_notes("arch-notion-oauth")returned no results. The OAuth handshake is documented, but underarch-dataflow-notion-mcp-remote(sequenceDiagram explicitly covering authorize/callback/token).[SCOPE]Either rename the label toarch:dataflow-notion-mcp-remoteor create a dedicatedarch-notion-oauthcomponent note. Recommend re-labeling since the dataflow note already covers this material. - [x] Forgejo issue —
https://forgejo.tail5b443a.ts.net/forgejo_admin/notion-mcp-remote/issues/6, open, created 2026-04-21
File Targets
This is credential provisioning — no repo file edits expected. The ticket correctly states this and lists downstream consumers:
- [x]
~/secrets/notion-mcp-remote/credentials.env— verified directory exists at~/secrets/notion-mcp-remote/ - [x]
server.py:19-20already readsNOTION_OAUTH_CLIENT_ID/NOTION_OAUTH_CLIENT_SECRETfrom env — verified via Grep - [x]
.env.example:2-3uses the same two key names — verified - [x]
k8s/deployment.yaml:43-52mounts both from secretnotion-mcp-secretskeysoauth-client-id/oauth-client-secret— verified - [x] "Do not touch" list is accurate —
server.pyandrequirements.txtcorrectly already consume these env vars
Repo Placement
OK — the issue is filed on
forgejo_admin/notion-mcp-remote and the credentials feed this service's secret. Sibling ticket #7 (k8s secret provisioning) and #8 (Woodpecker activation) are correctly split into separate issues because they touch different systems.Dependencies
Board scan (
board-notion-mcp-remote):- This ticket blocks:
- Not blocked by anything in in_progress — safe to pull.
- Dependencies implied in context ("Blocks ticket #5 / #8") per router brief do not match the actual board — ticket #5 is the Harbor/Woodpecker CI bug, and #8 is Woodpecker repo activation, neither of which consume Notion OAuth credentials directly.
[BODY]Clarify blocker chain in the issue body: this ticket unblocks #7 (secret provisioning) and #9 (E2E verify), not #5 and #8. (Or correct the router brief — this is a router-context issue, not a ticket-body issue, so noting for Ava.)
Acceptance Criteria
All 5 ACs are verifiable by an agent/human:
- Integration exists in Daily workspace — verifiable by loading the Notion integrations UI.
- Distribution is Public — same UI verification.
- Redirect URI exact — ISSUE: wrong path. The ticket specifies
https://notion-mcp-remote.tail5b443a.ts.net/callback, but the running service advertises and consumes/oauth/callback(confirmed inmcp-remote-auth/src/mcp_remote_auth/routes.py:41andprovider.py:125,151). Using/callbackwill cause Notion to reject the token exchange.[BODY]Fix redirect URI tohttps://notion-mcp-remote.tail5b443a.ts.net/oauth/callbackin the AC, the smoke curl, and the Constraints section. - Creds captured in
~/secrets/notion-mcp-remote/credentials.env— testable by file presence + key names. - Smoke curl returns consent HTML — valid once redirect URI is fixed.
[BODY] Optional consideration: the service also exposes /onboard/callback (onboarding flow, onboarding.py:136). Out of scope for the claude-ai-connect story, but if Lucas plans to use the same public integration for onboarding, that redirect URI should also be registered now to avoid a second manual trip to the Notion UI.Blast Radius
- Credential leakage: Constraint already calls out "do not commit CLIENT_SECRET to any git repo." Good.
- Redirect URI mismatch: If the wrong path (
/callback) is configured with Notion, the entire OAuth leg fails silently at the token exchange. The ACs as written would be marked green by an agent but the service would still be broken end-to-end — #9 (E2E verify) would catch it, but a lot of work happens in between. Fixing AC #3 prevents this. - Base URL drift:
BASE_URLenv var is the single source of truth; if the Tailscale Funnel hostname ever changes, the Notion integration redirect URI must be updated in the Notion UI. Worth a note in Constraints.
Decomposition Assessment
1 point, 5 ACs, no code edits, one UI flow. Well within the 5-minute rule. No decomposition needed.
Recommendation
Two concrete fixes required before this can move to
todo:[BODY]Fix the redirect URI path throughout the issue (AC #3, smoke curl URL in AC #5, Constraints, Test Expectations):/callback→/oauth/callback. This is the critical fix — the current path will silently break the handshake.[SCOPE]Resolve thearch:notion-oauthlabel: either (a) change the label toarch:dataflow-notion-mcp-remoteto match the existing architecture note, or (b) create a dedicatedarch-notion-oauthcomponent note. Option (a) is lighter weight and the existing note already captures the handshake.
Optional (non-blocking):
[BODY]Add/onboard/callbackas a second registered redirect URI if the same integration will back onboarding (future story).[BODY]Correct the blocker references in the ticket's lineage/related context (blocks #7 and #9, not #5 and #8) — or clarify router brief.