Skip to content

I1203 — One flow serves every provider, and it refuses everything it did not start

Implement the authorisation-code flow with PKCE once, over the typed provider model: a start route that issues state and nonce and redirects to the provider's authorisation endpoint, a callback route that refuses a state it did not issue or that has expired, exchanges the code, verifies the issuer, the audience, the expiry and the nonce of the returned identity token, and resolves the stable subject from the claim the object names.

BLOCKED wave 2 · p0 · implementation profile · runs alone

Part of web-sign-in — The deployed surfaces know who is asking, and the identity providers are data.

Blocked. This issue cannot start until I1202 is done. The status is derived from that, not declared.

Objective

Implement the authorisation-code flow with PKCE once, over the typed provider model: a start route that issues state and nonce and redirects to the provider's authorisation endpoint, a callback route that refuses a state it did not issue or that has expired, exchanges the code, verifies the issuer, the audience, the expiry and the nonce of the returned identity token, and resolves the stable subject from the claim the object names.

Why

Two provider-specific flows are two places for a validation to be forgotten. The differences between the providers this milestone starts with are spellings of endpoints, which the objects already carry.

Current state

I1202 gives the providers; there is no flow, no route and no verification.

Desired state

Signing in with either declared provider works end to end against the real provider, and every refusal path — unknown state, replayed state, expired state, mismatched nonce, wrong issuer, absent credentials — is exercised by a test.

Scope

  • apps/majordomus-cli/src/identity
  • apps/majordomus-cli/src/http
  • apps/majordomus-cli/tests
  • test/cases

Out of scope

  • Storing anything about the reader beyond the session of I1204
  • A provider-specific branch anywhere in the flow

Dependencies

What waits on this

Acceptance criteria

  • State and nonce are single-use, expiring, and bound to the provider they were issued for
  • The identity token is verified for issuer, audience, expiry and nonce before any session exists
  • A callback whose state was not issued by this server is refused without a session and without a redirect that leaks the parameters
  • The redirect target after sign-in is validated against the surface's own origin rather than taken from the request
  • Every refusal path has a test, and the tests run without contacting either provider

Validation

  • cargo test --workspace --all-features
  • bash test/run.sh

Evidence required

  • flow_single_implementation
  • refusals_tested
  • token_verified

Evidence

None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.

Risk

An open redirect and an unvalidated state are the two classic defects of this flow. Both are tested as refusals rather than assumed.

Timeline

started
verified
completed

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I1203.yaml. Read it back with majordomus plan show I1203.