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.

One browser login creates a session that can hold several contexts. API keys and partner OAuth are unaffected.

Start browser login#

Send POST /v1/oauth/device/authorize with an application/x-www-form-urlencoded body. Always include session_mode=contexts:

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

Send one credential per request. Combining a CLI bearer with X-API-Key or X-Checkout-Session-ID returns 400 AMBIGUOUS_AUTH when the request uses CLI OAuth authentication. A Flint-Merchant-Id, Flint-Mode, or Flint-Merchant-Environment-Id header that disagrees with the token's binding returns 403 OAUTH_CONTEXT_MISMATCH and identifies the header in param. Remove the header or sign in to the requested context. An invalid or expired grant returns 401 INVALID_OAUTH_TOKEN; unavailable OAuth authentication returns 503 OAUTH_UNAVAILABLE.

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.

To add permissions to one context without reviewing the rest, send scope_mode=additive with that context's context_id and only the scope names to add. The context's merchant and environment apply, so conflicting merchant_id, sandbox_id, or environment values return invalid_context. Approval adds the scopes the browser approved to that context and leaves every other context unchanged. The browser can approve a subset, so read the granted set from scope in the token response. Unsupported scopes, or scopes the environment does not allow, return invalid_scope.

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.

List authorized CLI contexts#

POST/v1/oauth/contexts

No 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. Read approved scopes from the selected context's token response or /v1/developer/auth-context. No business access is granted.

Response · 200

contextsarray of objectRequired
oauth_session_idstringRequired
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/authorize

No 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. Send session_mode=contexts for a session that supports additive reauthorization. The required scope field contains the full requested set as space-separated names. Normal login sends the unchanged x-flint-cli-bootstrap-scopes; login with extra permissions sends the desired baseline and additions. No scopes are implicitly added. The browser may approve a subset per context; token scope reports the approved set. Unknown scopes return HTTP 400 invalid_scope. Selected scopes are checked against the selected merchant and environment before approval.

Response · 200

device_codestringRequired
expires_inintegerRequired
intervalintegerRequired
user_codestringRequired
verification_uristringRequired
verification_uri_completestringRequired
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/reauthorize

No 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. Without scope_mode, approval replaces consent; denial or expiry leaves consent unchanged. Redeem using the device_code grant to rotate the latest family token. Set scope_mode=additive and context_id to request additional space-separated scope names for one existing context. Merchant and environment are derived from that context; conflicting hints return invalid_context. Approval unions only browser-approved additions with that context's existing scopes and preserves all other contexts. No implicit bootstrap scopes are added. Unsupported or environment-disallowed scopes return HTTP 400 invalid_scope; browser denial returns access_denied when polling. Partial approval succeeds and scope in the token response is authoritative. Legacy single-context sessions must start a new contexts-mode authorization.

Response · 200

device_codestringRequired
expires_inintegerRequired
intervalintegerRequired
user_codestringRequired
verification_uristringRequired
verification_uri_completestringRequired
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/revoke

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

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

Was this helpful?