Rename verified_email → service_auth, rework how the claim email is stored + managed#15
Rename verified_email → service_auth, rework how the claim email is stored + managed#15m0tzy wants to merge 3 commits into
Conversation
Promotes the email-based registration path out from under identity_assertion into a top-level `service_auth` type with a CIBA-style `login_hint` body, and replaces the /claim wrong-account 403 with advisory prompts (hint_mismatch, first_time_provider, first_time_account) that surface above the user_code form without blocking. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR promotes the email-based registration path out of
Confidence Score: 4/5Safe to merge after fixing the ID-JAG step-up wrong-account gap in store.ts. The findOrCreateIdJagRegistration function was not updated alongside the RegistrationClaim refactor: it still writes email to a field that no longer exists on the type, and crucially does not set login_hint on the RegistrationClaimAttempt it mints. Because hintMismatch in claim.ts reads attempt.login_hint, this field being absent means the wrong-account check always passes for ID-JAG step-up flows — any signed-in user can complete the ceremony and bind the matched delegation to their own account. All other flows (service_auth, anonymous) correctly populate login_hint and are unaffected. agent-services/src/store.ts — specifically the findOrCreateIdJagRegistration function's claim/attempt construction block. Important Files Changed
|
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Reverts the soft-advisory experiment from earlier in this branch. The
wrong-account hard reject is back: both GET /claim and POST /claim/complete
return 403 when the current attempt's login_hint doesn't match the signed-
in user. `hint_mismatch` advisory removed; `first_time_account` and
`first_time_provider` stay as informational notices.
Internal: `claim.email: string` → `attempt.login_hint: LoginHint = { kind:
"email", value }`. Per-attempt (not claim-level) so a re-mint via
`/agent/identity/claim` can correct the hint without being locked to the
first attempt. `/agent/identity` classifies the wire string at the edge
via `classifyLoginHint` and returns `invalid_login_hint` for anything that
isn't an email shape.
The `/agent/identity/claim` email-immutability check is gone — corrected
re-mints are the legitimate retry path, and the user-facing 403 is what
defends the user_code-interception case.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| 3. **You have neither** → [anonymous](#anonymous). Claim ceremony optional; deferred until the user wants to take ownership. | ||
|
|
||
| Before sending: cross-check your choice against the `agent_auth` block. If the matching `*_supported` array doesn't list your method, this service won't accept that registration shape — pick another or stop. | ||
| For `identity_assertion`, cross-check that your assertion type is in `agent_auth.identity_assertion.assertion_types_supported` — trust setup isn't enumerable by trial, so a missing entry means stop. For `service_auth` and `anonymous`, `identity_types_supported` is informational — send the body and fall back on the `*_not_enabled` error if the service opted out. |
There was a problem hiding this comment.
| For `identity_assertion`, cross-check that your assertion type is in `agent_auth.identity_assertion.assertion_types_supported` — trust setup isn't enumerable by trial, so a missing entry means stop. For `service_auth` and `anonymous`, `identity_types_supported` is informational — send the body and fall back on the `*_not_enabled` error if the service opted out. | |
| For `identity_assertion`, check that your assertion type is in `agent_auth.identity_assertion.assertion_types_supported`, if not listed then stop. For `service_auth` and `anonymous`, `identity_types_supported` is informational — send the body and fall back on the `*_not_enabled` error if the service opted out. |
Summary
Promotes the email-based registration path out from under
identity_assertionand into a top-levelservice_authregistration type with a CIBA-stylelogin_hintbody. The previous shape filed verified-email underidentity_assertionlike the agent was asserting something, but the agent is really just hinting at who the user is — the service does the verifying. CIBA's vocabulary fits, so this aligns with it. See the v0.7.0 CHANGELOG entry for the full wire diff.Internal rework of how the hint is stored: a new
LoginHint = { kind: "email"; value: string }lives on theRegistrationClaimAttempt(not the claim itself), so a corrected re-mint via/agent/identity/claimcan carry a corrected hint without being locked to whatever the first attempt bound. The route classifies the wire string at the edge viaclassifyLoginHintand returns a newinvalid_login_hinterror if it doesn't look like an email. The user-facing wrong-account 403 on/claimis preserved — the signed-in user must match the current attempt'slogin_hintto complete the ceremony.Discovery slim:
agent_auth.identity_assertion.assertion_types_supporteddrops"verified_email"(ID-JAG only now);identity_types_supportedgains"service_auth". AUTH.md Step 2 narrows the cross-check guidance — onlyidentity_assertionneeds to consult discovery;service_authandanonymousare send-and-fall-back on*_not_enabled.🤖 Generated with Claude Code