No SDK helper yet. The trust attestor’s OIDC side is live, but the reference SDK doesn’t ship a drop-in RP handler — you hand-wire the callback (roughly the same shape as a “Sign in with Google” route). It’s a small amount of standard OIDC code; the snippets below are complete.
Prerequisites
- A
service_didyou already use for attestation (§4.3) — sign-in reuses it, it is not a new identifier. - Agents that sign up attested (linked to their human), so accounts carry a
sub_h. See Preconditions if some accounts were created as guests first.
1. Register as an OIDC client
Ask the attestor operator to register your service. A client binds three things (§10.8.3):| Field | Value |
|---|---|
client_id | Your service identifier (your service_did is a fine value). |
service_did | MUST equal the aud / service_did you use for attestation. It is the audience input to the sub_h derivation — a mismatch lands humans in a different, empty account. |
redirect_uris | Exact callback URLs. Anything not on the allowlist is rejected before a code is issued. |
trust.afauth.org, the operator sets this in the TRUST_OIDC_CLIENTS environment variable:
2. The flow
Standard OIDC Authorization Code + PKCE (S256). Discovery is at https://trust.afauth.org/.well-known/openid-configuration.
3. Start the sign-in (authorize)
Generate a PKCE verifier + challenge and astate/nonce, stash them in a short-lived store keyed by state, and redirect:
4. Handle the callback (token + verify)
Exchange the code at the token endpoint, then verify theid_token against the trust JWKS:
jwtVerify checks the signature, iss, aud, and exp for you; the explicit nonce check closes the loop opened at the authorize step.
5. Resolve to the account — canonicalize the issuer
The account lives under(iss, sub_h), where sub_h is id_token.sub. The catch: your attestation path stored iss = "afauth-trust", but the id_token carries the URL. Map both to one issuer before you look up, or the human lands in a new empty account:
Preconditions
Sign-in resolves an account by(iss, sub_h), so the account needs a sub_h. That is written when an agent signs up attested (after linking to its human). Two cases to know:
- Attested signup, then sign-in — works immediately; the signup wrote
sub_h. - Guest signup, then link, then sign-in — the guest account had no
sub_h. Because signup is idempotent on the agent’sdid:key, the principal binds on the agent’s next attested request after linking. After that one request, sign-in resolves to the same account. (Until then, the human signing in would resolve to nothing and see “no account yet”.)
What sign-in does not do
Signing in authenticates the human to the(iss, sub_h) account — it does not transfer ownership. It does not run the claim ceremony or raise the §7.5 owner-binding floor. If you want a recoverable human owner (recovery contacts, credential enrollment), run a claim alongside sign-in — they compose. See §10.8.5.
Where to next
Sign in with AFAuth (concept)
The
(iss, sub_h) = OIDC (issuer, subject) idea, in full.Accept trust attestations
The agent-side gate that writes
sub_h in the first place.Invite and claim
Establish a recoverable human owner alongside sign-in.
Trust API reference
Full OIDC endpoint and
id_token shapes.