Device Sign-in: `banksync login --device` and the OAuth Device Grant

Sign a terminal or a machine without a browser into BankSync with the OAuth 2.0 device authorization grant (RFC 8628): the CLI flow, the endpoints, their errors and limits, and how to revoke it.

3 min read

On this page

Device sign-in signs a machine with no usable browser into BankSync: an SSH session, a container, a CI box you are logged in to. The machine shows a short code; you type it into BankSync in any browser where you're signed in, choose a workspace and approve. It is the standard OAuth 2.0 Device Authorization Grant, offered to BankSync's own CLI client (banksync-cli) only; the endpoints below document what the CLI does.

The result is an ordinary OAuth grant: scoped to the permissions you approved and to one workspace, refreshed like any other, listed under Settings, Developers, Connected apps, and revocable there.

Availability

Device sign-in is rolling out. While it is switched off, discovery still advertises the endpoint, but /device_authorization answers temporarily_unavailable (HTTP 503) and banksync login --device exits with device_login_unavailable. Use banksync login (browser) or an API key until then.

From the CLI#

Shell
banksync login --devicebanksync login --device --scope transactions:read,feeds:read
To sign in, open  https://app.banksync.io/deviceand enter the code  BCDF-GHJK
Check that the code there matches this one before you approve.Waiting for approval (expires in 10 minutes)...Logged in to Acme Books (profile: default).

The CLI stores the credential exactly as banksync login does. banksync logout forgets it on this machine; revoking it under Connected apps ends it everywhere.

The endpoints#

Discovery (https://auth.banksync.io/.well-known/oauth-authorization-server) advertises device_authorization_endpoint and the grant type urn:ietf:params:oauth:grant-type:device_code.

1. The client: banksync-cli#

The device grant belongs to BankSync's own command line. It uses the first-party public client banksync-cli, which BankSync defines itself, so there is nothing to register and no secret. Dynamic client registration refuses the device grant (invalid_client_metadata), and /device_authorization refuses any other client (unauthorized_client). That way the approval page only ever names a client BankSync vouches for. For your own tool, use banksync login --device and the CLI's stored credential, an API key, or the browser authorization-code flow.

2. Start: POST /device_authorization#

HTTP
POST https://auth.banksync.io/device_authorizationContent-Type: application/x-www-form-urlencoded
client_id=banksync-cli&scope=banks:read feeds:read&platform=linux

platform is a BankSync extension the approval page shows (web, windows, mac, linux, ios, android, other).

JSON
{  "device_code": "Q0hBTkdFLU1FLWl0J3MtYS0zMi1ieXRlLXJhbmRvbS12YWx1ZQ",  "user_code": "BCDF-GHJK",  "verification_uri": "https://app.banksync.io/device",  "verification_uri_complete": "https://app.banksync.io/device?code=BCDF-GHJK",  "expires_in": 600,  "interval": 5}

Show user_code and verification_uri, and ask the person to type the code. verification_uri_complete is for display (a QR code); the page still asks them to confirm the code against your screen. Keep device_code secret.

3. Poll: POST /token#

HTTP
POST https://auth.banksync.io/tokenContent-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=Q0hBTk...&client_id=banksync-cli

Wait interval seconds between polls. Until approval the answer is HTTP 400:

errorMeaningDo
authorization_pendingNot approved yetPoll again after interval seconds
slow_downYou polled too soonAdd 5 seconds to interval for good
access_deniedDenied, or the person was signed out or left the workspaceStop
expired_tokenTen minutes passed, or the grant was already issuedStop; start again
invalid_grantThe device code belongs to another clientStop

Once approved, one poll gets the standard token response (access_token, refresh_token, expires_in, scope). Refresh it with grant_type=refresh_token like any BankSync grant.

Limits#

  • /device_authorization is rate limited per IP, and /token per IP and per client; a limited request is HTTP 429 with Retry-After.
  • The person approving has a budget of five wrong codes in fifteen minutes.
  • While device sign-in is turned off, /device_authorization answers temporarily_unavailable (HTTP 503) and the approval page can't look up or approve a code, so a code issued before it was turned off ends in expired_token. /token itself isn't switched off: refreshing existing grants keeps working.

Revoking#

  • One device: Settings, Developers, Connected apps, or POST /revoke with its refresh token.
  • Sign out everywhere (POST /api/device-signin/sessions/revoke-all from the app) ends signed-in browser and Excel add-in sessions only. It does not end OAuth grants, API keys or SimpleFIN access, and its response says so in still_active; revoke those where they live.

Security notes#

  • Approving needs a sign-in from the last ten minutes that passed two-step verification when it's on, on a verified account. A session from the Excel add-in can never approve.
  • Only BankSync's own CLI client can start a device sign-in, so the approval page never shows a name someone else chose. It names the client, the permissions, the platform, when and roughly where the device asked, and you choose the workspace and may grant fewer permissions.
  • Never approve a code someone else sent you. BankSync staff never ask you to.

Use this page with your AI assistant

Every BankSync doc is available as plain Markdown for agents and LLMs.