Flows / Human in the loop

Backchannel approval (CIBA)

The agent asks the authorization server to go and find the user. Approval arrives as a push notification, not a redirect.

Based onOpenID Connect CIBA Core 1.0Final specGuide reviewedNovember 2026

Sources and review details
This page
Implementation guideAn explanation, not a specification
Primary specification
CIBAFinal spec · Final since September 2021
All 4 specifications
4 published
Flow maturity
Stable standardsWhat the rating means
Human involvement
Human reachable
Review
Checked against sources in November 2026How it was checked

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.

Step by step

9 steps between 4 parties. Each step shows the message and who holds which credential afterward. Use ←→ or select any arrow.

Sequence diagram4 participants, 9 steps
  • Direct call
  • Via the user’s browser or device
  • Response
  • Out of band
  • Local action

Drag to see every party and step. Tap a step to jump to its explanation.

1Reaches a gated action2Backchannelauth request3auth_req_id,interval4Push: “Payinvoice 1042?”5Authenticateand approve6Poll token endpoint7Token forthis payment8Releasepayment 10429201 Created

  1. 1AgentLocal action

    The agent needs approval it does not have

    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.

  2. 2Agent to Authorization serverDirect call

    The agent asks the server to get approval

    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"}]
  3. 3Authorization server to AgentResponse

    The server acknowledges

    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

    Agent
    newauth_req_id

    Parties not listed hold none of this flow’s credentials at this point.

  4. 4Authorization server to UserOut of band

    The server contacts the user

    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

    Agent
    auth_req_id

    Parties not listed hold none of this flow’s credentials at this point.

  5. 5User to Authorization serverVia the user’s browser or device

    The user approves on their own device

    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

    Agent
    auth_req_id

    Parties not listed hold none of this flow’s credentials at this point.

  6. 6Agent to Authorization serverDirect call

    The agent collects the result

    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

    Agent
    auth_req_id

    Parties not listed hold none of this flow’s credentials at this point.

  7. 7Authorization server to AgentResponse

    The server issues a narrowly scoped token

    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

    Agent
    newaccess token (invoice 1042 only)used upauth_req_id

    Parties not listed hold none of this flow’s credentials at this point.

  8. 8Agent to Payments APIDirect call

    The agent performs the approved action

    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

    Agent
    access token (invoice 1042 only)

    Parties not listed hold none of this flow’s credentials at this point.

  9. 9Payments API to AgentResponse

    Done, with a record of who approved

    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

    Agent
    access token (invoice 1042 only)

    Parties not listed hold none of this flow’s credentials at this point.

Watch out for

  • Approval fatigue. An agent that can trigger a push whenever it likes will train its user to tap “approve.” Rate-limit requests and make each one specific.
  • The 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.
  • The agent chooses whom to ask via login_hint. If an attacker can influence that value, they choose who gets prompted. Derive it from the authenticated session, never from model output.
  • CIBA support is uneven. It is common in financial-grade identity providers and less so elsewhere.

Approval is not the same as an agent pausing to ask

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.

Standards in play

See the full tracker for status and links.

Final specOpenID Connect CIBA Core 1.0

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.

RFCRFC 9396

Rich Authorization Requests

Consent for one payment or one file, not “payments” or “files.” The base of several agent proposals.

Final specOpenID FAPI 2.0

FAPI 2.0 Security Profile

A ready-made answer to “what should a high-stakes agent integration require?”