auth-oauth

Authorize Complete

User finished the /connect page — mint a short-lived code and return the redirect URL.

Auth: the user must be signed in (Clerk session cookie validated by the existing get_principal dependency). PKCE parameters and the redirect_uri come straight from the original client request via the keel-app page; we re-validate redirect_uri server-side.

Redirect validation, two mutually exclusive paths:

  • CIMD client (client_id is an HTTPS URL): fetch the metadata document; its redirect_uris are AUTHORITATIVE for this client.
  • otherwise: the hardcoded static allow-list.

The response redirect carries RFC 9207 iss (always) and honours an RFC 8707 resource indicator when the client sent one.

post/v1/auth/oauth/authorize-complete

Request

  • Base URL: https://api.usekeel.io (the document declares no server; this is the origin it was published from)
  • URL: https://api.usekeel.io/v1/auth/oauth/authorize-complete
  • Auth: none declared

Headers

Authorizationstring nullable
X-Org-Idstring nullable

Request body

redirect_uristring required

Where to redirect the browser with the issued code.

code_challengestring required

PKCE S256 code_challenge (base64url-encoded SHA-256 digest).

code_challenge_method'S256'

Only S256 is supported (plain is forbidden by OAuth 2.1).

statestring nullable

Opaque CSRF-protection value echoed back to the client.

include_liveboolean

True if the user checked 'Include live trading'. Adds runner.* to the granted scopes — but ONLY when requested_scope permits the live tier (see the field below). The review-aware consent page (D6) never shows the checkbox for a base-only request; this server-side gate is the fail-safe that holds even if include_live=on is submitted anyway.

requested_scopestring nullable

The OAuth scope request parameter the client sent to the authorization endpoint (space-delimited), forwarded by the /connect page. A value that is present and omits the live tier (the listed/directory connector requests scope=base) forbids minting runner.* regardless of include_live. Absent → no narrowing (full/custom-connector + CLI keep the checkbox-driven behavior).

include_execution_analytics_readboolean

True only when the user explicitly consented to detailed execution-analytics reads. The exact execution_analytics.read token must also be present in requested_scope; this flag alone never widens access.

include_execution_analytics_exportboolean

True only when the user explicitly consented to execution activity exports. The exact execution_analytics.export token must also be present in requested_scope; this flag alone never widens access.

client_namestring nullable

Display label for this connection (e.g. 'Claude Code'). Stored on the refresh-token row so the user can revoke individual clients from the settings page. Not used for auth or scope decisions — security comes from redirect_uri.

client_idstring nullable

OAuth client identifier. When it is an HTTPS URL it is treated as a Client ID Metadata Document (CIMD) per the current MCP auth spec: the server fetches the document and its redirect_uris become authoritative for this client (replacing the static allow-list). Non-URL client_ids are informational only.

resourcestring nullable

RFC 8707 resource indicator — the canonical URL of the MCP server the token is being requested for, forwarded by the /connect page from the client's authorize request. Must exactly equal a hosted endpoint this authorization server issues tokens for (invalid_target otherwise). Absent → unchanged behaviour and no aud on the minted token.

connect_attempt_idstring nullable

The platform.connect_attempts id the /connect page carried (the ca URL parameter, Q-2381). Analytics only: links the attempt to this principal and is stored on the code so the token exchange can stamp it. A malformed value is DROPPED, never rejected, so measurement can never fail a consent.

prompt_copied'clipboard' | 'select_fallback' | 'skipped' nullable

How the consent card's first prompt left the page (Q-2495): clipboard (the clipboard write resolved), select_fallback (the clipboard refused; the prompt was selected and the next click continued) or skipped (Return without copying). Absent for a card with no prompt (the Keel CLI). Measurement only: an unknown value is DROPPED, never rejected, so it can never fail a consent.

device_class'desktop' | 'ios' | 'android' | 'unknown' nullable

The consenting device's class (Q-2584), reduced by keel-app from the request UA AND the card's input hint (a coarse pointer). It only REVISES an attempt the server render recorded as desktop from the UA alone -- Chrome on Android's desktop-site mode sends a desktop UA. Measurement only: an unknown value is DROPPED, never rejected.

Response

Successful Response

redirect_tostring required

The full redirect_uri with code and state query parameters appended. The /connect page issues a 302 to this.

Changes

No recorded changes to this operation across all 1 revision of this API.