CLI OAuth

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:

text
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:

text
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:

JSON
{
  "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:

text
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:

text
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.

Send POST /v1/oauth/device/reauthorize:

text
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:

text
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.

List authorized CLI contexts#

POST/v1/oauth/contextsNo API key required

First-party public client flint-cli. Uses application/x-www-form-urlencoded and flat OAuth JSON without a Flint envelope. No client secret or HTTP Basic authentication. Requests are not replayed through idempotency caching. Flint session control extension. Authenticates the current refresh token without consuming or rotating it. Returns only currently authorized contexts, including an empty list. No business access is granted.

Response · 200
contextsarray of objectrequired
oauth_session_idstringrequired

Error codes

INVALID_REQUESTSERVICE_UNAVAILABLE
Bash
curl -X POST https://api.withflintpay.com/v1/oauth/contexts \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Start CLI browser login#

POST/v1/oauth/device/authorizeNo API key required

First-party public client flint-cli. Uses application/x-www-form-urlencoded and flat OAuth JSON without a Flint envelope. No client secret or HTTP Basic authentication. Requests are not replayed through idempotency caching.

Response · 200
device_codestringrequired
expires_inintegerrequired
intervalintegerrequired
user_codestringrequired
verification_uristringrequired
verification_uri_completestringrequired

Error codes

INVALID_REQUESTSERVICE_UNAVAILABLE
Bash
curl -X POST https://api.withflintpay.com/v1/oauth/device/authorize \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Review CLI session consent#

POST/v1/oauth/device/reauthorizeNo API key required

First-party public client flint-cli. Uses application/x-www-form-urlencoded and flat OAuth JSON without a Flint envelope. No client secret or HTTP Basic authentication. Requests are not replayed through idempotency caching. Flint session control extension. Starts device consent bound to the current session and user without consuming the refresh token. Approval replaces consent; denial or expiry leaves consent unchanged. Redeem using the device_code grant to rotate the latest family token.

Response · 200
device_codestringrequired
expires_inintegerrequired
intervalintegerrequired
user_codestringrequired
verification_uristringrequired
verification_uri_completestringrequired

Error codes

INVALID_REQUESTSERVICE_UNAVAILABLE
Bash
curl -X POST https://api.withflintpay.com/v1/oauth/device/reauthorize \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Revoke a CLI session#

POST/v1/oauth/revokeNo API key required

First-party public client flint-cli. Uses application/x-www-form-urlencoded and flat OAuth JSON without a Flint envelope. No client secret or HTTP Basic authentication. Requests are not replayed through idempotency caching.

Error codes

INVALID_REQUESTSERVICE_UNAVAILABLE
Bash
curl -X POST https://api.withflintpay.com/v1/oauth/revoke \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"
Rate this doc