Flint registers flint-cli as a public OAuth client, with no client secret or HTTP Basic authentication. Login uses OAuth 2.0 Device Authorization Grant, renewal uses the refresh-token grant, and logout uses RFC 7009 revocation. Context selection, context listing, and reauthorization initiation are Flint extensions.
Multi-context sessions are pending backend and CLI rollout. The contract below describes that release. Existing API keys, partner OAuth, and single-context CLI sessions keep their authorization behavior.
Start browser login#
Send POST /v1/oauth/device/authorize with an application/x-www-form-urlencoded body:
client_id=flint-cli&session_mode=contexts&scope=payments.payment_intents.read&environment=sandbox
The flat response contains device_code, user_code, verification_uri, verification_uri_complete, expires_in, and interval. Keep the device code private. Open the complete verification URI. The page shows the pairing code, preselects the obvious context, and lets the user add contexts or limit permissions before approving or denying. A context identifies one merchant and environment, plus a sandbox for sandbox access. Each context requires at least one permission. LIVE contexts are explicitly labeled and require approval.
Optional merchant_id and sandbox_id constrain consent. environment selects the initial token's environment and defaults to sandbox. It does not prevent explicitly approving additional live contexts. A sandbox request never falls back to live. Verification links contain only the pairing code and never approve access by themselves.
Exchange and refresh credentials#
Poll POST /v1/oauth/token using the returned interval:
grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=flint-cli&device_code=DEVICE_CODE
OAuth responses use flat JSON, without a Flint envelope. authorization_pending means keep waiting. slow_down means increase subsequent polling intervals by five seconds. access_denied and expired_token end the attempt.
Successful multi-context redemption returns:
{
"access_token": "ACCESS_TOKEN",
"token_type": "Bearer",
"refresh_token": "REFRESH_TOKEN",
"expires_in": 900,
"scope": "payments.payment_intents.read",
"oauth_session_id": "session_123",
"context_id": "ctx_123"
}
Each access token grants access to exactly one approved context. Send it as Authorization: Bearer ACCESS_TOKEN to merchant APIs. GET /v1/developer/auth-context returns the Flint envelope with auth_type=oauth, matching oauth_session_id and context_id, a stable oauth_grant_id, name, merchant, environment, sandbox, and token scopes. A context's merchant, environment, and sandbox never change. Its grant ID stays stable across refresh and reauthorization.
Select a context and renew access through POST /v1/oauth/token:
grant_type=refresh_token&client_id=flint-cli&refresh_token=REFRESH_TOKEN&context_id=ctx_123
Every successful refresh replaces the session refresh token. Save the replacement before making another request. invalid_context and context_access_denied leave that token unconsumed. Optional scope can reduce the selected context's permissions but cannot add them. Scope reduction invalidates earlier access tokens for that context. Ordinary rotation leaves unexpired access tokens for other authorized contexts valid.
Access tokens last 15 minutes. Sessions expire after 30 days without refresh or 90 days after login. Reusing a spent refresh token revokes the entire session, including when a successful response was lost. Do not retry a consuming request automatically. Start a new login after invalid_grant.
List authorized contexts#
Send POST /v1/oauth/contexts:
client_id=flint-cli&refresh_token=REFRESH_TOKEN
The response contains oauth_session_id and a contexts array. Each entry has id, name, merchant_id, environment, and, for sandbox contexts, sandbox_id. This operation checks the current refresh token without rotating or consuming it. It works with an expired access token or a removed selected context. An empty list is valid; reauthorize to request access again. Listing grants no business access. Responses fit within 64 KiB and have no pagination. A session can retain up to 100 context identities, including removed contexts.
Review session consent#
Send POST /v1/oauth/device/reauthorize:
client_id=flint-cli&refresh_token=REFRESH_TOKEN&session_mode=contexts&scope=payments.payment_intents.read&environment=sandbox&context_id=ctx_123
The optional merchant and sandbox constraints also apply here. The response is the standard device authorization response. Starting a review leaves existing consent and credentials unchanged. Browser consent shows current contexts and permits adding or removing access and reducing permissions. Approval invalidates tokens for removed or changed contexts immediately. Denial or expiry before approval leaves existing consent unchanged.
Redeem the device code through /v1/oauth/token. Redemption rotates the session's latest refresh token, even if it changed after reauthorization started, and preserves the session ID. Codes are single-use. A newer consent change invalidates older pending approvals or redemptions.
The returned token keeps the preferred context if it remains authorized, including a preferred LIVE context. Otherwise it selects an authorized sandbox. If none is available, consent must include a sandbox before approval can complete; the server never substitutes a different live context.
Revoke a session#
Send POST /v1/oauth/revoke:
client_id=flint-cli&token=REFRESH_TOKEN&token_type_hint=refresh_token
HTTP 200 with an empty body confirms completed or already-completed revocation. Previously rotated refresh tokens can revoke their own session. Revocation invalidates all access tokens across every context. Webhook streams recheck authorization and close when access is no longer valid.
flint logout --confirm revokes the session before deleting local credentials. If revocation fails, the CLI retains credentials for retry. Review other sessions at CLI sessions.
Existing single-context sessions#
Omitting session_mode=contexts keeps the single-context device flow and token response without session/context metadata. Ordinary refresh never upgrades an existing grant. API-key and partner OAuth authorization remain unchanged. The updated CLI replaces a legacy session through a new browser approval and revokes the old grant only after saving the replacement.
