CIBA
The established way for a background agent to ask a person for approval. The IETF agent architecture draft recommends it, while noting it fits approval before a task better than in the middle of one.
Flows / Human in the loop
The agent asks the authorization server to go and find the user. Approval arrives as a push notification, not a redirect.
An agent has been working for an hour. It reaches a step it is not allowed to take alone: send the payment, merge the change, email the customer. The user is not looking at the agent. There is no browser to redirect.
Client-Initiated Backchannel Authentication turns the flow around. The agent calls the authorization server directly and says which user it needs and why. The server contacts that user on a device it already knows, typically a phone, and shows them a message describing the request. When the user approves, the agent receives a token. Nothing is typed, nothing is redirected, and the user can be anywhere.
CIBA came out of banking, where a call-center agent or a point-of-sale terminal needs a customer’s approval on the customer’s own phone. That is the same shape as an AI agent asking its principal for permission.
9 steps between 4 parties. Each step shows the message and who holds which credential afterward. Use ←→ or select any arrow.
Drag to see every party and step. Tap a step to jump to its explanation.
The agent’s standing permissions let it read invoices and draft payments. Releasing a payment requires a fresh approval from Alice for this specific payment.
A direct, authenticated call. login_hint identifies the user. binding_message is shown on the user’s device so they can match the prompt to the action. With Rich Authorization Requests, authorization_details carries the transaction in structured form so the resulting token is good for this payment and no other.
POST /bc-authorize HTTP/1.1
Host: auth.example
Content-Type: application/x-www-form-urlencoded
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=eyJhbGciOiJFUzI1NiJ9…
&scope=openid payments.release
&login_hint=alice@example.com
&binding_message=Pay invoice 1042: $1,250.00 to Acme Ltd
&requested_expiry=300
&authorization_details=[{"type":"payment","invoice":"1042",
"amount":{"currency":"USD","value":"1250.00"},"payee":"Acme Ltd"}]The request is accepted but not decided. The agent receives an identifier for it and is told how often it may ask for the result.
{
"auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
"expires_in": 300,
"interval": 5
}Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
How is up to the server: a push to an authenticator app, a passkey prompt, a message in a workplace chat tool. What matters is that the channel was set up beforehand between the user and the server, so the agent cannot forge it.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The user authenticates (a biometric, a PIN) and approves or denies. They are talking to the authorization server, not the agent. If the details look wrong, denial is one tap.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
In poll mode the agent asks periodically. CIBA also defines ping mode (the server calls the agent back when ready, then the agent fetches the token) and push mode (the server delivers the token to the agent’s endpoint). Ping suits agents that can receive webhooks.
POST /token HTTP/1.1
Host: auth.example
Content-Type: application/x-www-form-urlencoded
grant_type=urn:openid:params:grant-type:ciba
&auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac1
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=eyJhbGciOiJFUzI1NiJ9…Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The access token carries the approved authorization_details. It is short-lived, and it authorizes one payment to one payee for one amount.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The API checks that the request matches the authorization details in the token. An agent that tries to pay a different amount, or pay twice, is refused.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The audit trail links the payment to Alice’s approval at the authorization server, and to the agent that asked for it.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
binding_message is what the human actually reads. “Agent requests access” is useless. “Pay invoice 1042, $1,250.00, to Acme Ltd” is a decision.login_hint. If an attacker can influence that value, they choose who gets prompted. Derive it from the authenticated session, never from model output.Many agent frameworks have a “human in the loop” feature where the agent stops and asks the user to confirm in the chat window. That is a useful control, but the agent enforces it, so a compromised or confused agent can skip it. CIBA moves enforcement to the authorization server and the API: without the user’s approval there is no token, and without the token the call fails.
See the full tracker for status and links.
The established way for a background agent to ask a person for approval. The IETF agent architecture draft recommends it, while noting it fits approval before a task better than in the middle of one.
Consent for one payment or one file, not “payments” or “files.” The base of several agent proposals.
Secretless client authentication, and the second leg of ID-JAG and identity chaining.
A ready-made answer to “what should a high-stakes agent integration require?”
Start with a weak token. When the agent reaches something sensitive, the API says so and the user is asked for exactly that.
For agents with no browser of their own: show a code, let the person approve on another device, and poll.
A tool needs the user to sign in somewhere else. It hands back a link, the user completes the flow in a browser, and the secret never touches the agent.
The baseline. A person signs in, approves specific scopes, and the agent receives a token that says so.