Skip to Content
Authentication

Authentication

Artos agent commerce uses three credential classes. The single most common integration bug is mixing them: the API identity guard prefers X-API-Key over a bearer, so a buyer-bound call that sends both resolves as the platform identity and the buyer (and their spend caps) are never loaded.

The load-bearing rule. On buyer-bound calls — crypto prepare_checkout_payment, crypto/complete_checkout, and every /account/mcp tool — send the buyer OAuth bearer only. Never attach X-API-Key to those calls. Everything else (catalog, cart, checkout create/update, card completion, store get_order) uses the platform key.

On Connect the bridge applies this rule for you. On the Build track the @artos-commerce/ucp-client SDK applies it too (UcpClient sends the buyer bearer only on buyer-bound calls and relays a 401 via onAuthChallenge) — but the SDK does not acquire or refresh the bearer. Obtaining it through the OAuth flow below is still yours.

Credential classes

ClassHow obtainedUsed for
Platform X-API-KeySeeded platform credential (ck_artos_agent.…) — the bridge holds itCatalog, cart, checkout create/update, store get_order, card complete_checkout
Buyer OAuth bearerOAuth 2.1 + PKCE consent via My ArtosCrypto prepare_checkout_payment + complete_checkout; all /account/mcp tools
AP2 mandateMinted as a compact ES256 JWS (bridge mints it on Connect)Authorization over the priced checkout terms — not a payment rail

The merchant client_credentials key is a fourth, store-owned variant of the platform key — see For merchants. For how to obtain a cross-store platform key, see Platform API keys.

Do you need CIMD? Only if you run the buyer OAuth flow (the Shopping agent path). On Connect the client (Claude, Cursor) brings its own CIMD; catalog crawlers and checkout handoffs never touch buyer OAuth, so they need none.

OAuth 2.1 + PKCE (buyer connect)

The buyer connects once and stays connected (~30 days) because the client silently swaps an expired access token for a fresh one using a rotating refresh token. Access tokens are short-lived (default 1h).

Discover the Authorization Server

curl https://api.artos.sh/.well-known/oauth-authorization-server
{ "issuer": "https://api.artos.sh", "authorization_endpoint": "https://my.artos.sh/oauth/consent", "token_endpoint": "https://api.artos.sh/ucp/oauth2/token", "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"], "response_types_supported": ["code"], "code_challenge_methods_supported": ["S256"], "token_endpoint_auth_methods_supported": ["none", "client_secret_post"], "scopes_supported": ["purchase:complete", "offline_access"], "client_id_metadata_document_supported": true }

Exchange the authorization code

POST /ucp/oauth2/token (form-urlencoded). Request offline_access during consent to receive a refresh token.

curl -X POST https://api.artos.sh/ucp/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=authorization_code \ -d code=AUTH_CODE_FROM_REDIRECT \ -d code_verifier=YOUR_PKCE_VERIFIER \ -d client_id=https://your-app.example/oauth-client.json \ -d redirect_uri=https://your-app.example/callback
{ "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600, "scope": "purchase:complete", "refresh_token": "rt_…" }

Refresh silently

curl -X POST https://api.artos.sh/ucp/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=refresh_token \ -d refresh_token=rt_…

Refresh tokens are single-use and rotated — store the new refresh_token from every response. Silent refresh only works if (1) the AS advertises offline_access, (2) the resource returns 401 with WWW-Authenticate: Bearer error="invalid_token", and (3) your client relays that 401 + header rather than flattening it into a transport error.

CIMD — client registration without pre-registration

Artos supports Client ID Metadata Documents (SEP-991): your client_id is a stable HTTPS URL pointing at a JSON document describing your client.

  • Host an oauth-client.json at a public URL and use that URL as your client_id. Any stable HTTPS URL works — the examples in these docs use https://your-app.example/oauth-client.json. (Artos hosts its own at https://profile.artos.sh/well-known/oauth-client.jsonwell-known without the leading dot is deliberate there, not a typo; unlike the UCP profile at /.well-known/ucp, CIMD does not require an RFC 8615 well-known path.)
  • List every redirect_uri you use (a callback not in the document is rejected with redirect_uri is not registered).
  • The API TTL-caches CIMD docs (default 600s); after editing, wait or restart the local API in dev.
  • For local mcp-remote dev, point --static-oauth-client-info at a CIMD doc and include http://localhost:8898/oauth/callback in its redirect_uris.

Scopes

Buyer OAuth (authorization code + refresh)

The Authorization Server advertises these scopes at consent (see AS metadata at /.well-known/oauth-authorization-server):

ScopeGrants
purchase:completeComplete a checkout / place an order
offline_accessReceive a refresh token (request at consent)

Buyer OAuth does not include orders:read. A signed-in buyer reads their own orders via buyer-account tools (get_my_order, list_my_orders) with the buyer bearer only — no extra scope.

Platform / merchant credentials

orders:read and purchase:complete are granted on platform API keys and merchant BYOK credentials (For merchants), not on buyer OAuth tokens. Store-scoped get_order requires a platform key (or merchant credential bearer) that was minted with the orders:read permission.

Trust tiers

TierHow achievedTypical use
anonymousNo credentialsCatalog browse / search
tokenValid API key or OAuth bearerCart, checkout, orders (with scopes)
signedValid RFC 9421 HTTP Message SignatureElevated agent-verified requests

Operations matrix

OperationMin tierPermission
Global / store cataloganonymous
Cart / checkout create/updatetoken
Complete checkouttokenpurchase:complete
Crypto prepare_checkout_paymenttoken (buyer bearer)purchase:complete
Store get_ordertoken (platform key / merchant cred)orders:read on the credential
Buyer account toolsbuyer bearer

Agent authorization & spend caps (crypto)

OAuth consent (Connected apps) is not sufficient for autonomous crypto checkout. The buyer must also authorize the agent under My Artos → Agents, which records a stored spending allowance:

  • maxPerOrderAmount — per-order ceiling (minor units).
  • dailyCapAmount — optional rolling daily cap; spentTodayAmount accrues against it.
  • currency and expiresAt.

The server enforces this allowance up front on every rail when the AP2 mandate carries a payment_mandate_id, and consumes it once on settlement. An agent can read the live caps via get_buyer_context. Exceeding a cap fails the completion before any order is placed.

Rate limits are planned but not implemented in Phase 1.

Last updated on