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 Path A the bridge applies this rule for you. On Path B 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 Path A)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.

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

ScopeGrants
purchase:completeComplete a checkout / place an order
orders:readRead store orders via get_order
offline_accessReceive a refresh token (request at consent)

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_ordertokenorders:read
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