Flow · consent
Human-in-the-loop via CIBA
The agent is unattended. It needs a specific approval on the user's phone before a sensitive tool runs.
Use the hop list beside the stage, or the phase labels, to jump. Every hop has Now, Why, the RFC, and chips — none are skipped.
Actors
Agent · OpenID provider · User (authentication device)
Sequence
Animated sequence · consent
CIBA — How does an unattended client get approval on another device?
Human-in-the-loop via CIBA
The agent is unattended. It needs a specific approval on the user's phone before a sensitive tool runs.
Now · 1/7· Discover· OpenID CIBAYou are here
Agent→OpenID provider·POSTs a backchannel authentication request: login_hint, scope, binding_message
POST the backchannel authentication endpoint with a hint for which user, the scope, and a binding_message the user will see.
Why There is no front-channel redirect. The client is unattended. This is not the authorization endpoint used by code+PKCE.
The unattended desk phones the notary instead of sending a browser link.
- backchannel_authentication_endpoint from the spec
- login_hint from the spec
- binding_message from the spec
Solid = from the spec
CIBA authenticates/consents a grant; it does not replace resource-server policy. For enterprise pre-approved app connections, XAA may avoid a prompt entirely — that is a different control.
Transcript
- 1
DiscoverAgent→OpenID providerOpenID CIBA
POSTs a backchannel authentication request: login_hint, scope, binding_message
POST the backchannel authentication endpoint with a hint for which user, the scope, and a binding_message the user will see.
Why There is no front-channel redirect. The client is unattended. This is not the authorization endpoint used by code+PKCE.
The unattended desk phones the notary instead of sending a browser link.
- backchannel_authentication_endpoint
- login_hint
- binding_message
- 2
GrantOpenID provider→AgentOpenID CIBA
Returns auth_req_id (and expires_in, interval)
The OP returns auth_req_id. Delivery mode was declared at registration: poll (default in this sequence), ping, or push.
Why auth_req_id is the handle the client uses at the token endpoint (poll) or correlates with ping/push. It is not an access token.
A ticket number for a grant that does not exist yet.
- auth_req_id
- expires_in
- interval
- 3
GrantOpenID provider→User (authentication device)OpenID CIBA
Notifies the authentication device with the same binding_message
The OP contacts the authentication device. The client holds auth_req_id and still has no token.
Why The user must see the same binding message the client showed. Do not skip notify.
A ping on the phone: is this the action you meant?
- binding_message
- authentication device
- 4
GrantUser (authentication device)→OpenID providerOpenID CIBA
Authenticates on the authentication device
The user proves who they are on the other device. The client still has only auth_req_id.
Why Authentication and consent are different hops. Unlocking the phone is not yet an approval.
The owner unlocks the phone. The permission slip is still blank.
- authentication
- 5
GrantUser (authentication device)→OpenID providerOpenID CIBA
Consents — approves or denies — on the authentication device
The user authenticates and consents on the other device. The client has not been told yet.
Why Consent happens off the agent's screen. That is the point of CIBA.
The owner signs on the phone, not in the agent's window.
- consent
- 6
GrantAgent→OpenID providerOpenID CIBA
Polls the token endpoint: grant_type CIBA + auth_req_id — authorization_pending
grant_type=urn:openid:params:grant-type:ciba with auth_req_id. Response is authorization_pending. The client still has no access token.
Why Do not skip the wait. Poll is the default shown here. Ping: OP POSTs the client notification endpoint, then the client polls once. Push: OP POSTs the tokens. Mentioning ping/push in Why is not a substitute for this hop.
Ask again with the ticket number. The pass has not been printed.
- token endpoint
- grant_type=ciba
- auth_req_id
- authorization_pending
- ping / push
- 7
GrantAgent→OpenID providerOpenID CIBA
Polls again after the wait — the user has now consented; OP delivers tokens
The client receives the access token (and maybe an ID Token). Never send auth_req_id to the API.
Why CIBA mints a grant. The RS still enforces audience and policy. If delivery were push, this hop is the OP POSTing tokens instead — same result, different transport.
The pass arrives after the phone said yes.
- access_token
- ID Token
Caveats
CIBA authenticates/consents a grant; it does not replace resource-server policy. For enterprise pre-approved app connections, XAA may avoid a prompt entirely — that is a different control.