Documentation
Device flow
RFC 8628 device authorization grant. Use when an agent has no browser and no inbound HTTP listener (CLI tools, CI runners, IoT).
The default backend route is /oauth/device (not the spec's /oauth/device_authorization). The SDK accounts for this — pass a custom path only if you've overridden the server config.
Run a flow
from shark_auth import DeviceFlow
flow = DeviceFlow(
auth_url="https://auth.example.com",
client_id="shark_agent_xxx",
scope="calendar:read",
)
init = flow.begin()
print("Visit:", init.verification_uri)
print("Code:", init.user_code)
# Or print verification_uri_complete which embeds the code.
token = flow.wait_for_approval(timeout_s=300)
print(token.access_token)
import { DeviceFlow } from "@sharkauth/sdk";
const flow = new DeviceFlow({
authUrl: "https://auth.example.com",
clientId: "shark_agent_xxx",
scope: "calendar:read",
});
const init = await flow.begin();
console.log("Visit:", init.verificationUri, "code:", init.userCode);
const token = await flow.waitForApproval({ timeoutMs: 300_000 });
begin() returns {device_code, user_code, verification_uri, verification_uri_complete?, expires_in, interval}.
wait_for_approval() polls /oauth/token with grant_type=urn:ietf:params:oauth:grant-type:device_code, respecting the server's interval, and returns the TokenResponse once the user approves.
DPoP-bound device flow
Pass a DPoPProver and the resulting token is sender-constrained.
from shark_auth import DPoPProver, DeviceFlow
prover = DPoPProver.generate()
flow = DeviceFlow(
auth_url="https://auth.example.com",
client_id="shark_agent_xxx",
scope="calendar:read",
dpop_prover=prover,
)
init = flow.begin()
token = flow.wait_for_approval(timeout_s=300)
# token bound to prover.jkt
const prover = await DPoPProver.generate();
const flow = new DeviceFlow({
authUrl: "https://auth.example.com",
clientId: "shark_agent_xxx",
dpopProver: prover,
});
Errors
DeviceFlowError (Python) / DeviceFlowError (TS) on:
expired_token — user did not approve in time
access_denied — user explicitly denied
slow_down — surfaced when poll interval is too tight (the SDK auto-backs off)
See also