An AI agent can request delegated sign-in for a browser-limited device, but it must not confuse a displayed device code, actual human consent, a valid token and a completed external task. OAuth device authorisation requires a trusted provider, a human-initiated transaction, a short-lived user code, compliant polling and independent verification of the resulting permissions.
Contents
- Why device authorisation needs more than a code on a screen
- Four actors, four responsibilities
- Starting a device transaction only when it is needed
- User codes, device codes and what each one proves
- Why a polling loop is a protocol, not a rapid retry trick
- A state machine for the specified error responses
- Worked case: interval changes and an expiring authorisation
- Phishing: legitimate login pages can be part of the attack
- Bind the token to the intended account, scope and task
- Polling load, retries and capacity at scale
- Accessible instructions and safe human comprehension
- Eleven failure modes and the narrowest repair
- Transfer case: two accounts on one shared workstation
- How device authorisation differs from PKCE, passkeys and service identities
- Limitations, provider differences and uncertainty
- Frequently asked questions
- Reader routes and original standards
Why device authorisation needs more than a code on a screen
An agent running on an input-limited device or terminal may need delegated access to an account, but it should not ask the user to type a password into the agent itself. The OAuth 2.0 device authorisation grant provides a specific alternative: the client requests a short-lived device transaction, shows a verification address and user code, and waits while the person independently completes authentication and consent at the authorisation server. The device then polls the token endpoint according to a defined schedule. Success is established by a token response and the server’s grant, not by the agent’s narration that it is now connected.
The immediate engineering rule is to bind every pending device transaction to the correct client, intended user interaction, scopes and expiry. The human should recognise the genuine service and intended request. An agent should not accept arbitrary verification links supplied by documents, chat messages or remote prompts, and it must not encourage users to enter a code for an unexpected sign-in. Device-code phishing abuses the very fact that a code shown in one context can authorise a different device if a person is tricked into completing the flow.
The primary specification is RFC 8628, OAuth 2.0 Device Authorization Grant. It defines parameters, polling behaviour, error handling and security considerations. Provider rules vary; the GitHub OAuth authorisation documentation and Microsoft identity platform device-code documentation illustrate implementations without turning provider examples into universal requirements. No actual account authorisation or token exchange was performed for this article.
Although the series explores agent engineering, artificial superintelligence has not been established. The design problem here is practical and current: a coding assistant, terminal utility, television app or other authorised client must gain delegated permissions while respecting human consent and protocol safety. A convincing interface is not enough; the grant and subsequent API operations need independent verification.
Four actors, four responsibilities
The resource owner is the human or other authorised principal controlling access. The device client is the application requesting delegated permissions. The authorisation server handles sign-in, consent, token issuance and the device transaction. The resource server accepts valid access tokens for permitted API requests. Some deployments combine these services, but the conceptual boundaries help expose which actor must verify each fact.
The device client cannot conclude that the person typed the correct code merely because the local screen displayed one. The authorisation server checks the user-entered code, associates it with the pending device transaction and decides whether the authenticated user authorises the requested scope. The device client later receives a token response or defined error. The resource server must separately enforce token audience, scope and other applicable conditions on protected resources.
A public client such as a distributed terminal program generally cannot keep a long-lived embedded client secret confidential. RFC 8628 explicitly discusses non-confidential device clients. An agent should avoid pretending that a string embedded in every distributed application constitutes strong proof of one particular installed instance. Permission boundaries are established by the grant, client registration and server policy rather than by secrecy assumptions contradicted by the deployment.
Device authorisation is distinct from authorisation-code flow with PKCE. PKCE protects exchange of an authorisation code in a different flow; device authorisation accommodates clients that cannot conveniently receive an interactive browser redirect. Do not switch between flows by swapping endpoint names while retaining the other protocol’s correlation assumptions.
An end-to-end receipt should identify the selected provider, registered client, authorised account context where discoverable, granted scopes, expiry and the specific permitted action that followed. It should not store the short-lived user code as a reusable password or present an access-token response as evidence that some unrelated write succeeded.
Starting a device transaction only when it is needed
Under the specification, a client sends a device authorisation request to the provider’s device endpoint with its client identifier and any required requested scope information. The server responds with a device_code for the client, a user_code for the human, a verification_uri, an expiry interval and possibly a polling interval. The two codes have different audiences. A device_code is used in back-channel polling; the short user_code is meant for the human’s browser interaction.
Clients should begin only when a person initiates the connection or the application’s authorised workflow genuinely calls for it. RFC 8628 says clients should not continuously start fresh device requests on every launch or in an uncontrolled renewal loop. A flood of abandoned transactions creates server load, confusing interfaces and an attractive opportunity for code-swapping attacks. Distinguish a request that is pending consent from an established authorised session.
Display the verified provider’s expected verification address alongside the code, explain which application seeks which permissions, and provide a cancellation path. If the provider supplies verification_uri_complete, it may encode the code into a complete address or alternate transmission; it should still be treated as authorisation-context data rather than a universal trust signal. A QR code should not hide the provider identity or make an unexpected request seem legitimate.
A high-assurance client can show the provider name, scopes and the action that triggered the request before the person opens the browser. The person should confirm the request is expected. If a third party sends a code and says ‘enter this to view a document’, that is a different context and may be a phishing attempt. The code is not a generic verification ticket proving a document or website is safe.
The agent must use a configured and verified issuer or authorisation server. A webpage asking the agent to authenticate at a lookalike host is untrusted content. A server’s documentation can specify legitimate endpoints; arbitrary page text cannot enlarge the agent’s permissions or rewrite where the user should enter an authorisation code.
User codes, device codes and what each one proves
A device_code is normally a long, opaque value that links token polling to a particular pending authorisation request. The client sends that value to the token endpoint together with its client identity and the appropriate grant_type. It is not normally meant to be spoken or shown to the human. The user_code is shorter and designed to be entered on the provider’s verification page. Both expire and belong to one transaction.
The existence of a user code proves that an authorisation request was created, not that it was initiated for a harmless purpose. An attacker can start a legitimate device authorisation request for the attacker’s client and persuade a victim to enter the associated code. If the victim approves, the token may go to the attacker’s waiting client. The provider’s domain can be entirely genuine while the transaction’s social context is fraudulent.
Therefore a warning that merely says ‘check whether the verification site is official’ is incomplete. The person also needs to ask which device and application initiated the request, whether they themselves intended to connect it, and which permissions they are giving. An authentic login screen can be used in an unauthorised transaction if the request origin and intent were manipulated.
The short user code must be resistant to guessing. RFC 8628 discusses user-code entropy, brute-force protection and request throttling. Servers, not device clients, are responsible for enforcing verification-attempt controls. A terminal app should not print repeated variants or try to defeat those controls to make an expired code usable.
Do not place pending user codes in public logs, screenshots, support tickets or search indexes. The code alone may not be a long-term credential, but while valid it is sensitive transaction data. Limit its exposure to the people who are supposed to complete the legitimate request, then discard it when the session completes, expires or is cancelled.
Why a polling loop is a protocol, not a rapid retry trick
Unlike browser redirect flows, a constrained device may have no direct return channel from the person’s browser. The client polls the authorisation server’s token endpoint while the human authenticates separately. The poll includes the device-code grant type and the issued device_code, with the required client identity or authentication for that client category. Polling must obey the server’s minimum interval.
If an interval is supplied, RFC 8628 requires the client to wait at least that many seconds between requests. If omitted, the default is five seconds. A response of authorization_pending means approval has not yet occurred and does not justify faster polling. A response of slow_down requires increasing the interval by five seconds for that and all subsequent requests in that transaction.
Connection timeouts are not proof that the user denied the request. RFC 8628 instructs clients to reduce polling frequency after a timeout; exponential backoff is recommended. A well-behaved program also respects expiry, local cancellation, service retry policies and a finite resource budget. It should not hammer the token endpoint in hope that a rate limit disappears.
The agent’s user-facing status can say ‘waiting for authorisation’, but it must never claim ‘connected’ until a valid token response is independently observed and accepted. When an API call subsequently fails, it should distinguish missing scope, expired access token, server failure and resource-level refusal. An access token is not a blanket exemption from resource-server authorisation.
Polling logic is an implementation concern, but it is also a consent and availability concern. A client that automatically starts another device transaction after every expiry might keep asking the person to approve unexpected requests. Stop the old transaction, explain why it failed, and let a new request begin through a clear, authorised interaction.
A state machine for the specified error responses
Represent the process with states such as not_started, code_issued, waiting, authorised, denied, expired, cancelled and error. Transitions should be driven by actual server responses and elapsed time. In the waiting state, authorization_pending retains the transaction and schedules the next permitted poll. slow_down also retains the transaction but extends the minimum interval. Neither is a failure that should immediately trigger a new device-code request.
On access_denied, stop polling and show that the person refused access. On expired_token, stop the expired transaction. The specification allows the client to start again after appropriate interaction; it does not instruct an agent to silently launch an endless series. For unexpected or generic OAuth errors, stop and handle them in accordance with the protocol rather than interpreting every error as merely another pending response.
When success arrives, validate the structure and expected semantics of the token response, handle transport securely and store credentials only in the application’s intended protected store. The exact token properties vary by provider. Avoid broad claims that every provider returns an ID token, refresh token or identical expiration field. Scope and audience must be verified where relevant to the API being accessed.
Network retry is not the same as repeating a state transition. If a response is lost, the authorisation server may have progressed while the device remains uncertain. The client should consult the same transaction without inventing a new user code prematurely. If the existing transaction expires, its identity and any pending result must not be conflated with a new transaction.
This is a useful place to separate device authorisation from general code integration safety. In both cases, external state must be read back, but OAuth adds human consent, short-lived codes and server-controlled polling intervals.
Worked case: interval changes and an expiring authorisation
Consider a fictional terminal application that receives a device-code response at time zero with expires_in=180 seconds and interval=5 seconds. No user is signed in yet. The minimum ordinary polling schedule would have a first request no sooner than t=5, then t=10, t=15 and so on, subject to runtime costs and the provider’s actual instructions. The number 180 is the lifetime of this illustrative transaction, not a promise about any named provider.
Suppose the first two polls at t=5 and t=10 return authorization_pending. The next poll at t=15 returns slow_down. The minimum interval must now increase from five to ten seconds and remain at least ten seconds for later requests. A subsequent request at t=20 would violate that new minimum if the earlier response occurred at t=15. The next eligible time, ignoring network latency and further policy constraints, is t=25.
Imagine the client correctly polls at t=25 and receives pending, then at t=35 receives pending again. A network timeout occurs during a poll at t=45. The standard says the client must reduce frequency, and doubling the current interval is one recommended response. If the client selects a twenty-second interval, it can schedule no sooner than around t=65, subject to request start or completion accounting and provider policy. This is an invented timeline, not an actual API log.
Now suppose the human approves through the official provider page at t=70, after that client’s last poll. A poll at t=85 can receive success if the transaction remains valid and all conditions are met. The token response, not the fact that the user saw a success screen, establishes what the client received. The human approval may precede the client’s observation of it; those are two different events.
Finally imagine no approval arrives before t=180. The client stops, reports expiration and discards the pending code. It should not keep polling at t=200 with an expired code or quietly generate a new one. The arithmetic demonstrates why expiry and backoff interact: an agent that waits politely may make fewer polls, but an aggressive agent does not gain entitlement to violate the protocol.
Phishing: legitimate login pages can be part of the attack
Device-code phishing is especially counterintuitive because the authorisation website may be the real provider. The attacker does not always need to forge the provider’s login page. Instead, the attacker creates a device transaction for a client it controls, then tells a victim to enter the accompanying user code under some false pretext. Approval authorises the waiting client’s request, not the supposed benefit described in the deceptive message.
The practical defence is context validation. Did the person start a sign-in on a device or command-line app they control? Is the provider asking them to connect that specific application? Are the scopes appropriate for the work? Did the request arrive unexpectedly through an email, message, search result or document? If context is inconsistent, decline it even when the provider address is authentic.
An AI agent should never pressure a person to complete an unexplained device-code login. It must not generate messaging that confuses document verification with account authorisation. If it needs a genuine OAuth connection, it should explain which service, client and permission the user authorised it to request. It should allow the user to review consent on the provider’s own interface.
Enterprise administrators may restrict or monitor device-code flows depending on their threat model. The Microsoft Entra application security operations guidance discusses environments in which device flow deserves scrutiny. Such policies are deployment-specific; a client must obey their real outcome instead of trying another issuer or alternative flow to evade organisational controls.
Consent is not the same as a safe content task. A model may receive an apparently innocent instruction inside a retrieved page to ‘connect your account here to continue’. A retrieved page is untrusted input. A separate explicit authorisation boundary should mediate any change to the agent’s credentials or service access.
Bind the token to the intended account, scope and task
After successful polling, the client must still ask whether it received permission for the intended operation. An account connection may be valid but belong to a different tenant, organisation or profile than the user meant. The same individual can have personal and work accounts. A web app may have resource identifiers with overlapping names across tenants. Human labels are not sufficient substitutes for provider-issued identity and resource checks.
Document the scopes requested and those actually granted, where the provider exposes them. Use the least permissions necessary for the task. If an assistant only needs to read selected files, do not ask for blanket account modification permissions. If a later action needs more scope, that is a distinct authorisation decision, not permission to reinterpret the original grant.
Token storage deserves an explicit boundary. Access tokens are bearer credentials in many deployments. An agent must not place them in the article body, markdown traces, public logs, analytics fields or untrusted tool outputs. Avoid sending the token to an endpoint merely because a retrieved document instructed it to. Verify provider and resource-server destinations from trusted configuration.
A successful token response does not demonstrate that the requested external side effect occurred. For example, receiving permission to create a draft is not evidence that the draft was created, and creating a draft is not publishing it. Every later API write needs its own acknowledgement and independent readback where possible. This is a separate form of verification from the OAuth handshake.
Short-lived credentials and revocation can change state while the agent operates. Treat expiry and access_denied as normal states. Do not assume that a previously successful sign-in grants permanent access, or that switching to a different account is harmless when the intended data owner is the first account.
Polling load, retries and capacity at scale
One terminal waiting for a human is easy to reason about. Thousands of terminals simultaneously polling a token endpoint make interval control a capacity decision. If 2,400 pending clients each poll exactly every five seconds, the simple average offered polling load is 2,400/5 = 480 requests per second, before any retries or synchronisation bursts. This is a theoretical arithmetic example, not a measurement of a real provider.
If the interval is raised to ten seconds, the simple average falls to 240 requests per second, assuming the same 2,400 clients and steady distribution. Synchronised polls could still create bursts much higher than the average. Randomising initial timing within permitted boundaries and limiting local concurrency may help infrastructure stability, but must not reduce the required minimum interval or override a server response.
An agent coordinating several users should track one state machine per device transaction, rather than sharing a global ‘connected’ flag. Each transaction has its own expiry, code, interval, provider, client and requested scope. Do not reuse a device code for multiple users, and do not mix a result from one tenant into another transaction. The resource owner to which a token belongs matters for every subsequent request.
When rate limiting or service downtime occurs, backoff and honest status reporting are preferable to silent account switching or creating fresh device codes. A success metric such as ‘98% of polls completed’ would be misleading: the actual reader outcome is whether valid authorised sessions were established with appropriate consent and no unintended cross-account access.
Capacity and safety are linked because the service’s throttling behaviour protects both availability and the guessing surface. Treat a slow_down response as a binding protocol instruction. It is not evidence the server is weak or an obstacle to bypass by parallelising clients.
Accessible instructions and safe human comprehension
A device can be constrained without being unusable. Its interface should explain clearly what code to enter, where to enter it and what account access will be requested. The verification address should be short enough to compare with a trusted provider name. A QR code may help, but the human must still be able to assess the intended account connection and the destination. Do not hide those facts in a decorative graphic.
For screen readers or non-visual devices, communicate the code and address in a way the intended user can perceive. RFC 8628 discusses non-visual transmission, including the concern that codes should be accessible only to people sufficiently close to the device. An audible code spoken across a public room might permit an observer to try the authorisation flow before the user. Accessibility does not mean ignoring transaction confidentiality.
Show code expiry in an understandable way, but do not promise that the server will accept an expired code. If the session has already ended, clear the old code and offer an explicit restart action. Explain that unexpected device-authorisation requests should be declined. This reduces the likelihood that a person confuses a legitimate login ritual with a generic instruction to approve unknown access.
An application should not tell users to paste passwords, passkeys or private MFA recovery information into the device-agent chat. The external provider is responsible for authenticating them. For related sign-in mechanisms, WebAuthn passkeys follow a different challenge and origin-verification model.
After the transaction, clearly name which account or organisation is connected where that information is available. The user should be able to disconnect and revoke permissions. An agent claiming to have connected an account must not substitute an attractive success animation for an actual authorisation receipt.
Eleven failure modes and the narrowest repair
One failure is confusing user_code with device_code. Repair the API contract and user interface so only the user code is shown to the person and the device code remains in the back-channel request. A second is accepting any verification URL returned by an untrusted webpage. Repair it with trusted provider configuration and a checked issuer.
A third failure is starting authorisation automatically and repeatedly on every run. Require a genuine initiated task. A fourth is polling faster than the server’s interval. Implement a monotonic-time waiting rule and tests. A fifth is failing to increase the interval after slow_down. Add an explicit state transition that persists the new lower bound across subsequent polls.
A sixth error is retrying after access_denied as if the user simply had not responded. Stop the transaction and respect refusal. A seventh is polling expired codes indefinitely. Keep an expiry clock and distinguish expiry from temporary network failure. An eighth is assuming a code entered on a legitimate provider page always belongs to the device the user intended. Teach transaction-origin checks and show the client identity.
A ninth failure is mixing two concurrent pending sessions and associating a token with the wrong account. Bind code, client, tenant and scope to one transaction record. A tenth is logging tokens or active codes into public traces. Protect sensitive fields and retain a minimal state record. An eleventh is declaring the external task complete immediately after token issuance, even though the later resource API has not been called.
In each case, fix the earliest violated boundary rather than adding a generic retry. The central evidence chain is user-initiated context, provider identity, pending code, polling compliance, authenticated consent, token response, permitted resource operation and verified result. Skipping one link produces a story that may sound complete but lacks an accountable external outcome.
Transfer case: two accounts on one shared workstation
Consider a fictional learning centre with a shared workstation that connects to an approved cloud document service for two staff members. The first instructor starts device authorisation for the centre’s work account, but then leaves. A second instructor sees the pending code on the screen and signs in with their personal account. The original terminal may receive a token, but that is not sufficient evidence that the intended work account is connected.
A reliable implementation binds the expected account or tenant requirement to the initiating task. After consent completes, it checks the provider’s authorised account context where supported and refuses to carry out a work-account write with a personal-account token. If the flow does not expose enough identity information for the high-risk task, stop for clarification or use a supported provider identity endpoint rather than guessing from the user’s display name.
Suppose the code was issued with interval=5 and expires_in=600, and the terminal has waited 25 seconds before approval. That leaves at most 575 seconds of code lifetime from issuance, before considering clock differences and network latency. It does not mean the resulting access token will expire 575 seconds later; token lifetime is a separate property determined by the token response and provider policy.
Now change the situation: the second instructor actually owns the intended work account but the terminal’s local account label is stale. The same checking rule helps rather than blocks indiscriminately. Verify the provider-issued account identity and the original authorisation contract, update the label only through an approved path and then proceed. The right response depends on evidence about the account, not assumptions about who is standing at the keyboard.
The transferable principle is that successful protocol mechanics and correct user intent are separate. A valid OAuth grant can still be the wrong grant for the job. External action remains bounded by the actual identity, scopes, resource and accountable owner.
How device authorisation differs from PKCE, passkeys and service identities
PKCE strengthens an authorisation-code exchange by binding the later code redemption to a verifier associated with the original request. It is commonly appropriate for native or browser-facing clients able to launch an interactive sign-in. Device authorisation instead relies on an input-constrained device and a separate browser, with a pending transaction observed by polling. Both involve user authorisation but have different messages, endpoints and attack surfaces.
WebAuthn passkeys are authenticators used in an authentication ceremony, not a replacement name for the device-code OAuth grant. Passkey security depends on challenges, relying-party identity and origin binding. A user may authenticate to the provider with a passkey while authorising a device-code transaction, but that does not eliminate the need to scrutinise which device-code transaction they are approving.
A service-to-service workflow with no human owner may use a different OAuth grant or workload identity mechanism. It should not create an imaginary person to approve a device code. The correct credential type follows whether the actor is a user-delegated client, a confidential backend service or another authorised principal. An AI agent’s ability to issue API calls does not change which authentication architecture the service requires.
Provider terminology and implementation details vary. Microsoft and GitHub document device flow but have their own registration rules, supported grant types and application-policy constraints. The RFC is the general standard; provider manuals control their specific endpoints. An integrator should record the exact provider and documented version being used.
Most importantly, authorisation is a boundary on agency. A powerful assistant can propose an account connection, but it cannot create permission by persuasion or tool invocation. The human and the provider remain responsible for actual consent and token issuance.
Limitations, provider differences and uncertainty
The device grant is not intended to replace browser-based OAuth in capable mobile apps, as RFC 8628 explicitly states. Prefer a provider-supported authorisation flow suited to the device and threat model. Some enterprises restrict device flow because of phishing risks. The agent must respect those controls, not evade them by changing client registrations or impersonating another application.
Exactly which tokens are issued, how long they last, and how identity or scope is represented depends on the provider and configured application. Do not invent a universal refresh token or require an ID token when the provider’s device-flow documentation does not promise it. The returned fields must be interpreted under the specific API’s supported contract.
No client-side design can completely prevent a determined user from willingly approving an attacker’s genuine device transaction. Clear warnings, scoped permissions, provider logging, consent review and policy enforcement help, but social engineering remains a human and organisational risk. Avoid promising invulnerability from a well-formed polling loop.
Technical guidance does not authorise an application to gather credentials for unrelated people. Logs and examples should not include live tokens or actual user codes. The numerical cases in this article are constructed to teach interval and capacity arithmetic; they are not reports of real authorisation attempts.
When security controls or connector permissions block a transaction, the correct status is blocked. A tool error, expired user code or denied approval is never an instruction to bypass authentication safeguards. Honest outcome reporting is a first-class engineering feature.
Frequently asked questions
What is OAuth device authorisation? It allows an internet-connected input-constrained client to request user-delegated access while the person signs in and approves through a browser on another device. The client polls for the outcome.
Is the user code a password? No. It is a short-lived identifier for one pending authorisation transaction. It should still be protected while active because another person may misuse an unexpected code.
Is a genuine provider verification page always safe? No. A legitimate page can authorise an attacker-initiated transaction. Verify that you initiated the expected connection and recognise its client and requested permissions.
What is the default polling interval if the server omits it? RFC 8628 requires a five-second minimum. An explicit interval or a subsequent slow_down response changes the applicable limit.
What does slow_down mean? The authorisation is still pending, but the client must add five seconds to its minimum polling interval for this and later requests in the transaction.
What happens when the code expires? Polling ends. A new user-initiated transaction can be started when appropriate, rather than reusing the old code or silently renewing it without context.
Does a successful access-token response prove the later API write succeeded? No. A resource operation must be attempted under its own permissions and independently verified.
Can agents use device flow for every cloud integration? No. Use the provider’s supported architecture, the correct grant for the client type, and the owner’s permission. Device flow is for particular constrained-client scenarios.
How does device flow differ from PKCE? Device flow uses a separate browser plus polling; PKCE binds redemption of an authorisation code to a verifier in a different OAuth flow.
Can a shared workstation mix sessions? Yes, if the software is poorly designed. Bind each pending transaction and token to its initiating context, expected account and scopes.
Reader routes and original standards
For an engineering team, begin by defining trusted providers, client registrations, acceptable scopes, account context, expiry behaviour, stop conditions, token storage and resource-operation readbacks. Implement one state machine per pending device transaction, with tests for authorization_pending, slow_down, access_denied, expired_token and network timeout.
For a reviewer, test unexpected sign-in prompts, wrong accounts, expired codes, consent refusal and concurrent pending sessions. Assess the human interface, not just the OAuth request fields. A client that polls perfectly but tricks the wrong person into approving is not a safe client.
For educators, treat this as an example of separating intention, delegation, evidence and outcome. A person may approve a request, a token may be issued, and a subsequent action may still fail. Each stage needs its own proof. Read the wider How Super Intelligence Works hub and education that transfers into life.
Primary sources: RFC 8628 (2019) for the grant and security rules; GitHub device-flow authorisation; Microsoft device-code protocol; and Microsoft identity application security operations. Validate each provider’s current availability and policy in the environment being integrated.
The examples are invented; no connection, code exchange or token issuance was performed here. The key practical result is a verifiable protocol and human-consent boundary, not a claim that every connected agent has received authority to act.