Skip to content

auth: validate the Forge Invocation Token as primary, binding control-Worker auth#2

Merged
MrCoder merged 3 commits into
masterfrom
fit-primary-auth
Jul 16, 2026
Merged

auth: validate the Forge Invocation Token as primary, binding control-Worker auth#2
MrCoder merged 3 commits into
masterfrom
fit-primary-auth

Conversation

@MrCoder

@MrCoder MrCoder commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Control Worker (gateway/authorize.ts, new): a request presenting a bearer token is authorized by FIT verification alone — binding, so a forged FIT is rejected even alongside a valid shared secret. No bearer → x-mini-sites-secret fallback (the CI/E2E/smoke credential, unchanged).
  • verifyForgeToken now enforces iss: forge/invocation-token and aud (app-ARI allowlist) per Atlassian's FIT requirements, and the remote JWKS resolver is memoized per isolate (it's on the hot path now).
  • Resolver routes control calls through invokeRemote() instead of api.fetch(url) — Forge attaches the FIT only to invocations routed through a declared remote; plain api.fetch is external egress and carries no token (observed live on dev: authorize logged via:"shared-secret" until the switch). Remote key derived from the existing per-env CONTROL_BASE_URL variable.
  • Manifest: both remotes gain the compute operation (required by invokeRemote) — module config, not a scope; no admin-consent impact. No auth: block needed (that only adds OAuth tokens).
  • Docs/comments corrected everywhere the old "no auth: block → no FIT" claim lived (CONTEXT.md, manifest, resolver, worker, e2e spec comment).

Closes the ECOHELP-145889 Q2.1 gap ("remote does not validate the FIT").

Test plan

  • TDD: 13 new unit tests (iss/aud rejection cases; authorize decision table incl. binding, bad-secret, no-credentials) watched fail, then pass — 224/224 green + typecheck.
  • Live on dev (deployed worker + Forge app, forge install --upgrade on lite-dev): real page render logs {"evt":"authorize","ok":true,"via":"fit","path":"/serve-url"} and the mini-sites serve; forged bearer + valid secret → 401 bad-token; no credentials → 401 no-credentials.
  • E2E api project asserts only 401/UNAUTHORIZED — unaffected; full E2E runs when this PR is marked Ready.

Release note: the manifest change means production sites need forge install --upgrade after the prod deploy, and the ECOHELP-145889 reply should quote the release version.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UDYKDJBU8KZP9SWMaxNxSp

MrCoder and others added 3 commits July 16, 2026 17:29
…th (ECOHELP-145889)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDYKDJBU8KZP9SWMaxNxSp
…(api.fetch egress carries none)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDYKDJBU8KZP9SWMaxNxSp
@MrCoder
MrCoder marked this pull request as ready for review July 16, 2026 08:23
@MrCoder
MrCoder merged commit 8b7f885 into master Jul 16, 2026
5 checks passed
@MrCoder
MrCoder deleted the fit-primary-auth branch July 16, 2026 08:29
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