Skip to content

docs(adrs): propose app-signed identity tokens for interactive web users - #249

Draft
alukach wants to merge 1 commit into
mainfrom
docs/adr-015-app-signed-identity-tokens
Draft

alukach wants to merge 1 commit into
mainfrom
docs/adr-015-app-signed-identity-tokens

Conversation

@alukach

@alukach alukach commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Proposes ADR-015. The web app would sign a five-minute RS256 JWT for the session's Ory identity and exchange it at /.sts. That replaces the server-driven Hydra authorization-code flow ADR-004 describes, which costs four to six sequential calls through the Ory admin API before every web mint. The proxy would trust the app's issuer as a person issuer, with its own audience, under ADR-009's per-issuer audience rule, and fetch the app's JWKS through the cache it already has.

It amends ADR-004's "Identity Sources in Use — Interactive web users". The amendment note on ADR-004 itself is left until this is accepted.

Why now

Edit Mode in source.coop is slow, and most of the wait is this chain. source.coop#636 removes what the app can remove on its own: it reuses credentials across toggles, starts the mint when the menu opens, and drops a duplicate whoami. The first mint each hour still pays for every Hydra call. A review of that work across performance, security and OAuth practice concluded that the remaining latency, and the ADR-004 "become any user" admin-API cost, both come from not using a grant the proxy can verify directly.

How it relates to earlier ADRs

  • ADR-005 already has the proxy assert any sub to the Source API with its own short-lived JWT; this is the same trust in the opposite direction.
  • ADR-013 called a source.coop-signed JWT verified via a source.coop JWKS the right trust direction, and rejected it only for long-lived API keys (keys retained forever, exp vs an editable record). Neither applies to a five-minute token that is never stored.
  • ADR-004 deferred RFC 8693 until audit logs need to tell "the web app on the user's behalf" from "the user". Logging iss provides that.

Numbering

#219, an older draft, also adds an adrs/015-* and adrs/016-*. Its service-accounts ADR has since merged as 014, so whichever lands second renumbers.

Testing

Docs only. Claims about existing behavior were checked against adrs/ on main and source.coop's src/lib/actions/proxy-credentials.ts.

🤖 Generated with Claude Code

ADR-015 proposes that the web app sign a five-minute RS256 JWT for the session's identity and exchange it at /.sts, replacing the server-driven Ory Hydra authorization-code flow (four to six sequential calls through the Ory admin API) on the credential path. The proxy trusts the app's issuer as a person issuer with its own audience, per ADR-009's per-issuer audiences, and fetches the app's JWKS through its existing cache. It amends ADR-004's identity sources for interactive web users.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @alukach's task in 16s —— View job


✅ No blocking issues — safe to merge.

Docs-only ADR. The claims I checked are internally consistent: the "five to seven calls" figure matches the "four to six Ory calls plus /.sts" in Context, and the references to ADR-004, 005, 009, 013 and 014 are used consistently.

Non-blocking notes

  • adrs/015-app-signed-identity-tokens.md:58-62: the rotation steps can break web mints. Step 2 (sign with the next key) must not deploy until the proxy's JWKS cache has picked up the key published in step 1, which takes up to about 15 minutes. If it does, tokens carry a kid the proxy hasn't seen, so exchanges fail. Step 3 already has a wait. Add one between steps 1 and 2, or state that the proxy refetches the JWKS on an unknown kid.
  • :48: previews share the staging private key, so any branch's code can mint any person's staging credentials. That is probably acceptable for staging. The Costs section only calls out the key as a "become any user" credential generally, so say that explicitly here.
  • :52: the ADR depends on ADR-009's audience rule applying to person issuers. Confirm that 009 actually generalizes this way. If it only covers platform issuers, say so under "Amends"/"Depends on".

Simplify (ponytail)

  • :40: drop jti. It is "for log correlation only" and the proxy keeps no replay list. iat plus sub already correlate the logs, and this removes one claim to generate.
  • :68: drop the "configuration switch" for keeping the Hydra flow. A plain revert or a feature flag already in the app is enough, so no new switch needs its own design.

💰 Estimated review cost: $0.11 · 0m16s · 4 turns

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

🚀 Latest commit deployed to https://source-data-proxy-pr-249.source-coop.workers.dev

  • Date: 2026-10-05T01:37:17Z
  • Commit: 664f58e

This branch was successfully deployed

1 active deployment
preview — ce4edfee Deployed Oct 5, 2026 by alukach via Deploy & Test / Deploy #412
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant