CIBA and the OAuth device flow both let a user approve access on one device for a session that lives on another, but they put the start of the flow in different hands, and that single difference decides who can attack it and how. In the OAuth 2.0 Device Authorization Grant (RFC 8628) the device shows a code and the user carries it to a phone or laptop. In OpenID Connect Client Initiated Backchannel Authentication (CIBA) the client already knows who the user is and asks the identity provider to send them an approval request. This guide compares the two on initiation, user binding, client types, phishing exposure, FAPI requirements and fit for AI agent approvals, then gives decision criteria and two worked scenarios. It is for identity architects, IAM engineers and teams designing TV, CLI, call centre or agent approval flows.
Key takeaways
- The user starts the device flow; the client starts CIBA. In RFC 8628 the user must carry a code from the device to the verification page. In CIBA the client names the user with a hint and the identity provider contacts the user's registered device.
- The device flow's code channel is unauthenticated. Anyone can start a device flow and send the code to a victim, which is why device code phishing works on the genuine sign-in page and why RFC 10027 says to use the grant only when no other cross-device protocol is viable.
- CIBA trades code phishing for unsolicited requests. RFC 10027 calls CIBA less susceptible to unauthenticated channel attacks, but anyone who knows or can guess a user identifier can trigger prompts, so binding messages, user codes and rate limits carry the weight.
- Client type differs in practice. RFC 8628 says devices should generally be treated as public clients. CIBA requires the client to authenticate to the backchannel endpoint, and the FAPI CIBA profile allows only confidential clients with signed requests and no push mode.
- For AI agents asking a human to approve an action, CIBA is the better fit. The agent backend knows the user, can describe the transaction, and can wait for tokens scoped to that action. The device flow suits an agent or CLI that must sign itself in for a user who is present.
The short answer
Use the device flow when a device with limited input (a smart TV, a conference room system, a headless CLI) needs the user to sign in, the user is standing in front of it, and the device has no way to know who the user is before they act. Use CIBA when the client already holds an identifier for the user and needs that user to approve something on their own trusted device: a call centre verifying a caller, a till requesting a payment approval, or an AI agent pausing before a risky action. Where the user is on the same device that needs the session, use neither: the authorisation code grant with PKCE is correct, and RFC 10027 says cross-device protocols should not be used for same-device scenarios.
Before either, check whether FIDO2/WebAuthn cross-device authentication (passkeys over the hybrid transport) is possible. RFC 10027 recommends it because Bluetooth proximity proves the two devices are near each other, which neither code transfer nor backchannel triggering can do. See the Cross-Device Flow Security Guide for the full set of patterns.
Side by side
| Dimension | OAuth 2.0 Device Authorization Grant (RFC 8628) | OpenID Connect CIBA Core 1.0 |
|---|---|---|
| Status | IETF Standards Track RFC, August 2019 | OpenID Foundation Final specification, 1 September 2021 |
| Who initiates | Device calls the device authorisation endpoint; the user then acts on the code | Client calls the backchannel authentication endpoint naming the user; the OP contacts the user |
| What the client knows about the user up front | Nothing | An identifier, passed as exactly one of login_hint, login_hint_token or id_token_hint |
| How the user is reached | User types user_code at verification_uri or scans verification_uri_complete | Push or app notification on a registered authentication device |
| Binding between devices | The user code itself; the server should display it so the user can confirm it matches the device | binding_message shown on both devices; optional user_code known only to the user |
| Client type | Devices should generally be treated as public clients (RFC 8628 section 5.6) | Client must authenticate with its registered method; shared secrets in the request are discouraged |
| Token delivery | Polling with grant type urn:ietf:params:oauth:grant-type:device_code | Poll or ping (fetch from the token endpoint) or push (tokens sent to the client's endpoint) |
| Request handle | device_code, which should have very high entropy | auth_req_id, minimum 128 bits, 160 recommended, single use |
| Main attack | Remote phishing: attacker starts the flow and sends the code (section 5.4) | Unsolicited requests and request floods against a known identifier |
| RFC 10027 position | Use only if other protocols are not viable; avoid for sensitive, high value or business critical resources | Use instead of the device grant when the client can obtain a user identifier; still needs mitigations |
| FAPI 2.0 status | Not named in the FAPI 2.0 Security Profile | Named, with the authorisation code grant, as having detailed security analysis |
Both flows can carry structured permissions: RFC 9396 (Rich Authorization Requests) lists device authorisation requests and backchannel authentication requests among the places authorization_details may be used. See the OAuth Rich Authorization Requests (RAR) Guide.
Device flow: architecture and threat model
Architecture in words
The device sends its client_id (and client authentication if it is a confidential client) to the device authorisation endpoint. It receives a device_code it keeps to itself, a short user_code, a verification_uri, an optional verification_uri_complete for QR codes, expires_in and an optional polling interval, which defaults to 5 seconds. The device shows the code and URL. The user opens the URL on a phone or laptop, signs in with whatever the identity provider demands and enters the code. Meanwhile the device polls the token endpoint. It receives authorization_pending until the user finishes, must add 5 seconds to its interval on slow_down, and stops on access_denied or expired_token.
Threat model
- Remote phishing: RFC 8628 section 5.4 describes the attack directly. The attacker starts a flow on their own machine and persuades the victim to enter the code. The victim authenticates on the real identity provider, satisfying MFA, and the attacker's device receives the tokens. See the Device Code Phishing Guide for campaigns and detection.
- User code guessing: section 5.1 notes short codes have limited entropy and gives an example of an 8 character base-20 code at about 34.5 bits, which needs rate limiting on the verification page.
- No client trust signal: because the device is usually a public client, the authorisation server cannot tell a genuine TV app from an attacker's script using the same
client_id.
Controls that change the outcome
- Restrict who may use it: block the device flow by identity provider policy for users and applications that do not need it, with a documented exception group. Most workforce users never need it.
- Scope down: tokens from the device flow should carry the narrowest scopes, short lifetimes and, where the device can hold a key, sender constraint with DPoP (RFC 10027 sections 6.1.9, 6.1.10, 6.1.12). See the DPoP Guide.
- Short-lived, one-time codes: expire codes in minutes and reject reuse; detect the same code being submitted from many places.
- Explain the approval: the verification page should say a device is being signed in, name the application and, if known, the device type and location, and make "Deny" as prominent as "Approve".
- Trusted devices: where devices are managed (meeting room systems, signage), only allow the flow from registered devices or known networks.
CIBA: architecture and threat model
Architecture in words
The client discovers the backchannel_authentication_endpoint and registers one token delivery mode. To start, it authenticates to the backchannel endpoint and sends scope containing openid, exactly one hint, and optionally a binding_message, a user_code, acr_values and requested_expiry. The OP returns an auth_req_id and expires_in, contacts the user's authentication device, shows the binding message and authenticates the user. In poll mode the client calls the token endpoint with grant type urn:openid:params:grant-type:ciba; in ping mode the OP tells the client's notification endpoint that a result is ready; in push mode the OP sends the tokens to that endpoint, and the ID token then carries hashes of the access token, refresh token and auth_req_id. An auth_req_id is no longer valid once redeemed. Mode details and error handling are in the OIDC CIBA Guide.
Threat model
- Unsolicited requests: a malicious client or user who knows someone's phone number or email can start a flow against them. CIBA's optional
user_codeexists to stop this; the client must not store it but ask the user each time. - Request floods and fatigue: RFC 10027 notes that requests can be triggered without the user touching the consumption device, so an attacker can flood users or time requests for when they are tired. It is the same human weakness as MFA push fatigue: in the Cisco breach 2022 repeated push requests and voice phishing led an employee to approve one. See the MFA Fatigue and Bypass Guide.
- Weak binding: a binding message the user does not compare is worthless; the FAPI CIBA profile suggests stronger alternatives such as QR codes or ephemeral identifiers where comparison is unreliable.
- Misdirected results: in ping and push modes the OP posts to the client's notification endpoint, so the OP must check that endpoint is under the client's control or it may deliver results to the wrong party.
Controls that change the outcome
- Authenticate the client strongly: CIBA requires client authentication and recommends not sending shared secrets in the request; use
private_key_jwtor mTLS. See the JWT Client Authentication (private_key_jwt) Guide. - Sign the hint and the request: a signed
login_hint_tokenstops rogue clients harvesting identifiers; a signed request object proves the request came from the registered client. - Bind the transaction: put the amount, payee or action in the binding message or in
authorization_details, so the user approves a specific thing, not "a sign-in". - Rate limit per user and per client: cap outstanding requests per user, and treat repeated declines or timeouts as an attack signal rather than a reason to retry.
- Prefer poll or ping to push: tokens then come from the authenticated token endpoint; the FAPI CIBA profile forbids push.
FAPI and high-assurance requirements
For regulated payments, open banking and other high-value APIs, the choice is mostly made for you. The FAPI 2.0 Security Profile, Final on 22 February 2025, supports only confidential clients, requires client authentication by mTLS or private_key_jwt, requires sender-constrained access tokens by mTLS or DPoP, and names the authorisation code grant and CIBA as the two flows that received detailed security analysis. It does not mention the device authorisation grant, and RFC 8628's own advice to treat devices as public clients sits outside FAPI's confidential-only scope.
| Requirement | FAPI CIBA profile (Draft-02, 15 August 2019) | Effect on design |
|---|---|---|
| Client type | Authorisation server shall only support confidential clients for CIBA | No CIBA from mobile apps or browser code; the initiator is a backend |
| Request integrity | Signed authentication requests; nbf and exp limit the request to no more than 60 minutes | Client needs a signing key and JWKS; replayed requests expire |
| Binding | Unique authorisation context or a binding_message | Every prompt identifies the transaction |
| Delivery mode | Poll required, ping allowed, push not supported | Tokens are always fetched from the token endpoint |
| Hints | login_hint should not carry intent IDs; nonce-like hints recommended | Use the authorisation context for payment intent, not the hint |
| Cryptography | PS256 or ES256; TLS 1.2 or later | Avoid RS256 and none for request objects |
The FAPI CIBA profile page states it is a draft for review and not an OpenID Foundation standard, so check its current status before quoting it in a compliance document. See the FAPI 2.0 Security Profile Implementation Guide and the OAuth 2.1, GNAP and FAPI Guide.
AI agents: approvals versus sign-in
Agents use both flows, for different jobs, and confusing the two is a common design error.
- Agent asks a human to approve an action (CIBA): the agent backend knows which user it acts for. Before a payment, data export or production change it calls the backchannel endpoint with that user's hint, a binding message describing the action and, ideally,
authorization_details. The user approves on their phone and the agent receives an access token scoped to that action. The approval is an OP event tied to the user, the client, the authentication context and the request ID, which is far better evidence than a chat reply. See the Human-in-the-Loop for AI Agents Guide and the AI Agent Action Approvals and Spending Limits Guide. - Agent tool or CLI signs in as the user (device flow): a headless tool running in a terminal or container cannot open a browser, so it shows a code. This is acceptable only when the user is present, started the tool themselves and the scopes are narrow. It is also exactly the pattern an attacker imitates, so if the tool can open a local browser, the authorisation code grant with PKCE is better.
- Agent acts without any user: neither flow applies. Use client credentials or workload identity. See the Machine-to-Machine OAuth (Client Credentials) Guide.
An agent that can trigger CIBA requests is itself a powerful initiator. Treat its client credential as a privileged non-human identity, limit which users and which acr_values it may target, and cap requests per user per hour, otherwise a prompt-injected agent becomes a fatigue engine.
Decision criteria
- Is the user on the device that needs the session? Yes: authorisation code with PKCE. Stop.
- Can both devices do passkeys over the hybrid transport? Yes: prefer that for sign-in, combined with the code grant.
- Does the client know the user before the user acts? Yes, and the user has a registered authentication device: CIBA. No: device flow.
- Is the resource sensitive, high value or business critical? Yes and you are considering the device flow: redesign, or deploy proximity or trusted-device controls first, as RFC 10027 advises.
- Is this a FAPI or regulated payments context? Yes: CIBA under the FAPI profile, confidential client, poll or ping, sender-constrained tokens.
- Is the initiator an AI agent? Approvals: CIBA. Sign-in of a user-operated tool: device flow with narrow scopes, or a browser-based code flow where possible.
Small versus large organisations: a small organisation on a cloud identity provider mainly needs to switch off the device flow for everyone who does not need it and require transaction binding on push approvals. A large organisation running its own authorisation server must also own notification endpoint validation, hint signing keys, per-client rate limits and which users each agent client may target.
Worked scenarios
Scenario 1: meeting room displays and a developer CLI
A company has 300 conference room displays and an internal CLI that developers run in remote containers. The displays need a calendar account; the CLI needs a developer's token for an internal API. Neither knows the user in advance, so CIBA does not fit. The team allows the device flow only for the display application's client ID from the corporate network and registers the displays as managed devices. For the CLI, they switch to the code grant with PKCE and a localhost redirect where a browser is available, keeping the device flow as an exception for containers, with a 30 minute access token, no refresh token and a single API scope. They alert on device flow sign-ins outside the exception group.
Scenario 2: an AI agent that pays supplier invoices
A finance team deploys an agent that drafts supplier payments. Payments over a threshold need the approving manager's consent. The agent backend registers as a confidential CIBA client using private_key_jwt, in poll mode. For each payment it sends the manager's pairwise subject as an id_token_hint, a binding message "Pay invoice 4471, 12,400 GBP, ExampleCorp" and matching authorization_details, with acr_values requiring phishing-resistant authentication. The access token it receives is sender-constrained and valid only for that payment. The OP caps the agent at five outstanding requests per manager, and two declines in a row suspend the agent and page the finance owner.
Detection and measurement
- Log by grant type: record device code and CIBA grants separately from code flow sign-ins, with client ID, IP, user agent and the location of both the requesting and approving device.
- Device flow signals: sign-ins outside the exception group, code redemption from an IP or country different from the approval, and new device registrations soon after a device flow sign-in.
- CIBA signals: bursts of requests to one user, requests with
unknown_user_idresults (identifier probing), high decline or expiry rates per client, and notification endpoint delivery failures.
Metrics:
- Device flow sign-ins per week outside documented exceptions (target zero).
- Share of CIBA requests carrying a transaction-specific binding message or
authorization_details(target 100 percent for agent clients). - CIBA decline and timeout rate per client, with alerts on spikes.
- Percentage of CIBA and device flow tokens that are sender-constrained.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | PR.AA-03, PR.AA-05, DE.CM-03 | Authenticating users and services; scoping what approvals grant; monitoring cross-device sign-ins |
| NIST SP 800-53 Rev. 5 | IA-2(13) Out-of-band Authentication | CIBA's separate authentication device is an out-of-band channel |
| NIST SP 800-53 Rev. 5 | IA-9 Service Identification and Authentication; SC-23 Session Authenticity | Client authentication and binding the approval to the right session |
| NIST SP 800-53 Rev. 5 | AC-12 Session Termination; SI-4 System Monitoring | Short token lifetimes and revocation; detection of abuse |
| MITRE ATT&CK | T1566.002 Spearphishing Link; T1528 Steal Application Access Token; T1550.001 Application Access Token | Delivery of device codes or pretexts, and use of the resulting tokens |
| MITRE D3FEND | D3-TB Token Binding | Sender-constrained tokens limit the value of tokens obtained by phishing |
Common failure patterns
- Leaving the device flow on for everyone: most users never need it, yet it stays enabled tenant-wide and becomes the phishing route.
- Using CIBA prompts that say only "approve sign-in": without a transaction in the prompt, CIBA is just push MFA with an API, and fatigue attacks follow.
- Shared secrets on CIBA clients: a leaked secret lets anyone start approval requests in the client's name. Use asymmetric client authentication.
- Push mode by default: tokens sent to a notification endpoint widen the interception surface; use poll or ping unless latency truly demands push.
- Long-lived refresh tokens from cross-device grants: the approval was the weakest moment, so its tokens should be the shortest lived.
Practitioner checklist
- Inventory every client allowed to use the device grant or CIBA, with an owner and a reason.
- Block the device flow by policy except for named clients, users or managed devices.
- Register CIBA clients as confidential, with
private_key_jwtor mTLS, and poll or ping mode. - Require a transaction-specific binding message or
authorization_detailson every CIBA request from an agent. - Enable a user code or signed
login_hint_tokenwhere unsolicited requests are a realistic threat. - Rate limit CIBA requests per user and per client, and alert on repeated declines.
- Issue narrow scopes, short lifetimes and sender-constrained tokens from both grants.
- Document the RFC 10027 risk assessment for each cross-device flow you keep.
Standards and references
- IETF: RFC 8628 OAuth 2.0 Device Authorization Grant
- OpenID Foundation: OpenID Connect Client-Initiated Backchannel Authentication Flow, Core 1.0
- IETF: RFC 10027 Best Current Practice for Security of Cross-Device Flows
- OpenID Foundation: FAPI 2.0 Security Profile
- OpenID Foundation: Financial-grade API Client Initiated Backchannel Authentication Profile
- IETF: RFC 9396 OAuth 2.0 Rich Authorization Requests
- MITRE ATT&CK: Steal Application Access Token
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: OIDC CIBA Guide · Device Code Phishing Guide · Cross-Device Flow Security Guide · Human-in-the-Loop for AI Agents Guide