Human-in-the-Loop, Automated: Asynchronous Authorization for High-Stakes Agent Actions
Part of the series The Authentication and Authorization Challenges of Agentic AI.
Some agent actions are fine to take autonomously. Others — refunding a customer, deploying to production, moving money — genuinely warrant a human saying yes to that specific action, not just to the agent’s existence in general. The problem is structural: the moment an agent decides it needs that approval is rarely the moment a human happens to be looking at a screen. This is the consent gap, and how you close it says a lot about whether “human-in-the-loop” is a real control or a compliance decoration.
Why the obvious fix doesn’t work
The obvious fix is a one-time consent screen: when the agent is first set up, ask the user to approve it broadly — “allow this agent to manage your calendar, send emails, and process refunds on your behalf” — and let it run unsupervised after that. This technically satisfies “the user consented,” but it satisfies it the way a EULA does: broad, generic, granted once, and functionally meaningless as an ongoing control. It doesn’t distinguish between the agent rescheduling a meeting and the agent issuing a $2,000 refund. Once granted, it can’t be un-granted for one specific action without revoking the whole thing.
The opposite failure is just as common: requiring synchronous, in-session approval for every sensitive action, which only works if the user happens to be actively using the application at the exact moment the agent needs the answer. Most agent value comes precisely from not requiring that — background processing, multi-step workflows, actions that complete minutes or hours after the user last looked at anything. A consent model that only works synchronously quietly pushes teams back toward the broad one-time checkbox, because that’s the only way to keep the agent useful.
The pattern: decoupled, asynchronous authorization
The standards-based answer here is a decoupled authentication flow — defined by the OpenID Foundation as Client-Initiated Backchannel Authentication — that lets a client (the agent’s backend, in this case) request user authorization without the user being present in the same session, or even the same device, as the request. The agent’s backend sends the authorization request to the authorization server; the server pushes a notification to the user’s separate, trusted device — a phone with an authenticator app, typically — where the user reviews and approves or denies; the agent’s backend polls (or is notified) for the outcome and proceeds once approval lands.
Three delivery modes are defined, each suited to a different agent architecture: poll, where the client periodically checks whether a decision has been made — simple, and a reasonable default for most agent backends; ping, where the authorization server notifies the client that a decision is ready, reducing unnecessary polling traffic; and push, where the full result is delivered directly to the client, minimizing latency for cases where speed matters most. None of these require the user to be at the same screen, or even the same device, as the agent that triggered the request — which is the entire point.

Making the approval mean something: Rich Authorization Requests
A decoupled approval flow only solves half the problem. If the notification the user receives just says “approve access?”, you’re back to the meaningless-consent problem, just spread out over time instead of granted once upfront. The other half is Rich Authorization Requests (RAR, RFC 9396), an OAuth extension that lets an authorization request carry structured, specific authorization_details instead of a flat scope string.
The difference in practice is the difference between a notification that says “allow agent to access billing?” and one that says “approve a refund of $2,000 to customer Jane Doe for order #12345?” The second is the one that constitutes actual, meaningful, non-repudiable consent — the user is approving a specific, described action, not a category of access that happens to include it. When these are combined — decoupled authentication carrying a rich, structured authorization payload — you get an approval flow that works asynchronously and produces an audit record of exactly what was approved, in terms specific enough to hold up if anyone later asks whether the agent exceeded what it was given permission to do.
Design guidance
Reserve this pattern for genuinely high-stakes actions, not everything. The value of an approval prompt is inversely proportional to how often it fires. If every agent action — including routine, low-risk ones — triggers a push notification, the pattern degrades into exactly the approval fatigue it was meant to avoid, just on a per-action basis instead of a one-time basis. Decide, deliberately, which categories of action clear the bar for explicit approval (irreversible actions, financial transactions above a threshold, anything touching production infrastructure) and let the agent operate autonomously within its already-granted scope for everything else.
Make every approval request specific enough to be a real decision. If the structured authorization payload could be satisfied by more than one action the agent might plausibly take, it’s not specific enough. “Approve a transaction” is not the same as “approve a $2,000 refund to order #12345” — only the second gives the human something concrete to evaluate, and only the second produces a record that unambiguously shows what was approved if the agent’s actual behavior is later questioned.
Design explicitly for the no-response case. Asynchronous approval means the human might never respond — busy, asleep, phone dead. Decide up front what the agent does after a timeout: does the task fail safely, get queued for retry, escalate to a different approver, or expire outright? Leaving this undefined tends to produce systems that either hang indefinitely or silently proceed without approval, which defeats the entire mechanism.
Log the approved payload alongside what was actually executed. The value of a rich, structured approval request isn’t just the better user experience in the moment — it’s that you now have a machine-readable record of exactly what was approved, comparable after the fact against exactly what the agent did. If those two things can drift apart (the agent gets approval for one refund amount and, due to a bug or a later change in context, executes a different one) and nobody’s comparing them, the audit trail is decorative rather than functional.
Be honest about the UX and infrastructure cost. This pattern requires a trusted, reachable, out-of-band channel to the user — typically a registered device with a push-capable authenticator, or a phone number, or a verified email address the user actually monitors. Standing that up is real infrastructure, not a checkbox, and it’s part of why this pattern belongs on the small set of genuinely sensitive actions rather than everything an agent does.
Handled well, this is the mechanism that lets “human-in-the-loop” mean something more than a marketing phrase: not a human watching every action, but a human specifically and verifiably signing off on the handful of actions where that matters, in language precise enough to constitute real evidence of what they agreed to.
Next in the series: Beyond the Consent Screen: Agent-to-Agent and Agent-to-App Trust, which covers what happens to consent and delegation once agents start reaching into applications and other agents beyond the ones you directly control.