Agentic Authentication & Authorization - Part 6: Human in the Loop

Nov 14, 2026 min read

Agents act while the user is somewhere else. Sooner or later a decision needs a person: to grant access in the first place, to prove it is really them, to approve something they cannot approve alone, or to confirm one specific action. This part maps each of those moments to the standard that handles it, and to the one rule that cuts across all of them.

That rule comes from the IETF’s draft on AI agents, draft-ietf-wimse-aims: a confirmation shown in the agent’s own interface does not, by itself, constitute authorization. It has to map to a verifiable grant, such as a token issued after the user approved on a channel the agent does not control. The agent must not treat a local “OK” as enough. A prompt-injected agent can draw its own confirmation dialog.

Four moments a human is needed

MomentThe questionWho answersStandard
ConsentMay this agent act for me at all, and how far?The user, once, up frontOAuth authorization code; RFC 9396 for detail
Step-upIs this still really me, with strong enough authentication?The user, at the authorization serverRFC 9470; MCP scope challenges
ApprovalShould this access be granted, by someone allowed to grant it?An approver, often not the userAuthZEN Access Request and Approval Profile (draft)
ConfirmationDo I want this specific action, now?The user, on a device they trustCIBA; MCP URL-mode elicitation for third-party flows

The first human moment is the OAuth consent screen, and it is usually too vague to mean much. “Finance Assistant wants to access your payments” tells the user little about what the agent will actually do.

Rich Authorization Requests (RFC 9396) make consent specific. Instead of a scope string, the client sends authorization_details: an array of typed objects describing exactly what is requested. The RFC’s own example is a payment_initiation object with actions, an instructed amount and currency, and the creditor’s name and account. The RFC says this detail is what the authorization server needs to inform the user and obtain their consent. For an agent, that turns “access payments” into “pay up to 250 EUR to this creditor”, and the resulting token carries the same limits.

The MCP spec adds consent duties of its own. Authorization servers that accept Client ID Metadata Documents must clearly show the redirect URI’s hostname and should warn when every redirect URI is localhost (Part 4). MCP servers that proxy a third-party API with a static client ID must get the user’s consent for each dynamically registered client, to close the confused-deputy hole.

Step-up: more scope, or stronger authentication

Two different challenges look alike and are easy to confuse.

More scope. The MCP spec’s own step-up (Part 4): the server answers 403 with error="insufficient_scope" and the scopes it needs, and the client re-authorizes for the union of old and new scopes. The user may see a consent screen again, but nothing proves who they are more strongly than before.

Stronger authentication. RFC 9470, the OAuth 2.0 Step Up Authentication Challenge Protocol (September 2023), covers the case where the token is fine but the login behind it is not. The resource server answers with error="insufficient_user_authentication" and one or both of:

  • acr_values: the authentication context classes it will accept, in order of preference, such as one that requires a phishing-resistant authenticator;
  • max_age: the most seconds allowed since the user last actively authenticated.

The client sends the user back to the authorization endpoint with those values, gets a new token, and retries. The new token records what happened in acr and auth_time. If the authorization server cannot meet the request, it should return unmet_authentication_requirements rather than a token that will fail again.

The MCP spec does not list RFC 9470 among its references. But an MCP server is an OAuth resource server, and nothing stops it using this challenge for high-risk tools. A rule like “payments require authentication in the last five minutes” maps to max_age=300.

Both kinds of step-up need the user at a browser. That is fine for an agent in a chat window, and a problem for one running in the background. That is the case CIBA solves.

Out-of-band approval with CIBA

OpenID’s Client-Initiated Backchannel Authentication (CIBA Core 1.0, Final) was built for a client that cannot redirect the user’s browser, which describes most background agents. The client asks the authorization server directly; the user approves on a separate authentication device, typically their phone. draft-ietf-wimse-aims names it as the human-in-the-loop mechanism for agents, because the agent never touches the user’s credentials.

With CIBA the user approves on their own device; the agent sees no credentialsAgent (client)Authorization serverUser's phoneMCP server1 backchannel request2 auth_req_id, interval3 binding message: approve?4 user approves5 poll token endpoint6 access token7 tools/call with the new token
With CIBA the user approves on their owndevice; the agent sees no credentialsAgent(client)AuthorizationserverUser'sphoneMCPserver12345671backchannel request2auth_req_id, interval3binding message: approve?4user approves5poll token endpoint6access token7tools/call with the new token

The steps, in poll mode:

  1. The agent POSTs to the authorization server’s backchannel_authentication_endpoint, authenticating as it would at the token endpoint. It sends scope (including openid), exactly one hint identifying the user (login_hint, id_token_hint or login_hint_token), and a binding_message.
  2. The server returns an opaque auth_req_id, its expires_in and a polling interval, 5 seconds by default.
  3. The user’s device shows the request with the binding message, for example “Approve transfer of 250 EUR, code 4F7K”. The same message appears on the device where the request started, so the user can check they match.
  4. The user approves, or doesn’t.
  5. The agent polls the token endpoint with grant type urn:openid:params:grant-type:ciba and the auth_req_id.
  6. Once approved, it receives the tokens.
  7. It retries the tool call with the new token.

The delivery mode is fixed when the client registers. Besides poll, there is ping, where the server calls the client’s notification endpoint and the client then fetches the tokens, and push, where the server sends the tokens directly. Ping and push need a client_notification_token and an HTTPS notification endpoint, and push needs extra protection for that endpoint.

For agents, the binding message does the important work. It is what lets the user see that the approval on their phone is for this transfer, and not one a prompt-injected agent made up. Make it specific: amount, payee, a short code.

draft-ietf-wimse-aims also marks the limit. CIBA covers flows the client starts. Interrupting an agent mid-task to ask the user something, at different stages of execution, may need more standards work.

Approvals after a deny: the AuthZEN Access Request and Approval Profile

Sometimes the user cannot approve the action themselves: the agent needs access the user does not have, or policy requires a manager or a second person. The AuthZEN Access Request and Approval Profile (Draft 1, November 2026, an OpenID AuthZEN working-group draft) standardizes what happens after such a deny.

  1. The PDP marks the deny as requestable. It returns decision: false with a context.access_request object. expires_at is required; endpoint, template, display hints and a binding_token are optional.
  2. The PEP submits a request. It POSTs the denied subject, resource and action, plus the denial values echoed unchanged, to the given endpoint or the PDP’s access_request_endpoint. It may add context, a requested end time and an emergency flag.
  3. The service returns a task. A 201 or 202 with a task id, status and status_endpoint.
  4. The PEP waits. It polls the status endpoint with exponential backoff and jitter, honouring Retry-After, or receives a callback defined by a companion profile. Statuses are pending, approved, denied, expired, cancelled and failed, and anything unknown counts as not approved.
  5. On approval, the PEP asks again. It runs a new evaluation with the approval object in context.approval. The approval never grants access on its own; the PDP decides again, with the approval as evidence.

The security rules are what make this safe for agents:

  • A requestable deny is still a deny. The PEP must not grant anything because access_request is present.
  • The PDP must not authorize on a known approval ID alone. It must check the approval against trusted state or integrity-protected material: subject, resource, action, scope, expiry and revocation.
  • approval.approved_until bounds everything. The PEP must not use the approval after it, and any downstream credentials must expire by then.
  • Approver eligibility and separation of duties are enforced before approval, and emergency is a request signal, not an override.
  • Approval IDs and review links should not be forwarded to end clients, which for us means: keep them away from the agent.

Asking the user from inside MCP: elicitation

MCP has its own way for a server to ask the user something mid-request: elicitation. It has two modes, and they have very different roles.

Form mode collects structured data through the MCP client, using a flat JSON schema. Servers must not use it for sensitive information: passwords, API keys, access tokens or payment credentials. Clients must show which server is asking and offer clear decline and cancel options, and the user answers with accept, decline or cancel. Form mode is fine for “which account should I use?”. By the rule at the top of this part, it is not an authorization for “move the money”.

URL mode sends the user to a web page outside the client, for interactions that must not pass through it. Its main use is third-party OAuth: the MCP server acts as an OAuth client to another service and needs the user to authorize it. The spec’s rules here are strict:

  • URL mode is not for authorizing the MCP client to the MCP server; that is MCP authorization (Part 4). Servers must not use it to authorize users for themselves.
  • Third-party credentials must not pass through the MCP client, and the server must not use the client’s token at the third party, which would be token passthrough.
  • The server must check that the person who completes the flow is the same user who triggered it. Otherwise an attacker can send the link to a victim and end up with tokens bound to the attacker’s session.
  • Clients must show the full URL, must not open it without explicit consent, must not pre-fetch it, and must open it where neither the client nor the model can see the content or the user’s input.

One gap to know about: COAZ-MCP (Part 5) leaves server-initiated requests, including elicitation/create, out of scope in its current draft. Elicitations are not checked by the PDP.

Choosing the mechanism

Start from the situation the agent is in, not from the standard:

SituationUseWhy not the alternatives
The agent needs a well-defined grant, such as a payment limit, before it startsRAR (RFC 9396) at consentScope strings are too coarse for the user to judge
The token lacks a scope for this toolMCP insufficient_scope step-upNothing about the user’s authentication is in question
The action needs a recent or stronger login, and the user is at a browserRFC 9470 with acr_values or max_ageCIBA works too, but a redirect is simpler when the user is there
The action needs the user’s approval and they are not at the agent’s screenCIBA with a binding_messageAn in-agent dialog is not authorization (draft-ietf-wimse-aims)
The access must be approved by someone else, or needs separation of dutiesAuthZEN Access Request and Approval ProfileCIBA asks only the user; approvals need an approver and an audit trail
The MCP server needs the user to connect a third-party accountMCP URL-mode elicitationForm mode must not collect credentials, and passthrough is forbidden
The agent needs a non-sensitive choice from the userMCP form-mode elicitationIt gathers input, not authorization

Standards status (November 2026)

StandardStatus
RFC 9396, Rich Authorization RequestsRFC (May 2023)
RFC 9470, Step Up Authentication ChallengeRFC (September 2023)
OpenID CIBA Core 1.0OpenID Final (2021)
AuthZEN Access Request and Approval ProfileOpenID working-group draft, Draft 1 (November 2026)
MCP elicitation, form and URL modesMCP revision 2026-07-28; URL mode was introduced in 2025-11-25 and may still change
AI Identity Management System (draft-ietf-wimse-aims)WIMSE working-group draft -01, Informational

Sources