Skip to content

Customer Auth

Customer

Customer Auth groups 3 operations on the customer tier.

Customer authentication endpoint — called without a customer token, since this is how one is obtained.

POST

/api/{version}/customer/auth/token

Exchange a grant for an access + refresh token bundle. Accepts application/x-www-form-urlencoded (the OAuth2 default) or a JSON object. Dispatches on grant_type: authorization_code, password (ROPC), or refresh_token.

Both the success and the failure body are OAuth2 shapes, not this API's { errors } envelope — see CustomerTokenResponse and OAuthErrorResponse.

AuthenticationAnonymousCustomer authentication endpoint — called without a customer token, since this is how one is obtained.

Responses

curl -X POST \
  'https://<your-shop-domain>/api/2026-04-01/customer/auth/token' \
  -H 'Accept: application/json'
Response200example shape
{
  "access_token": "string",
  "token_type": "string",
  "expires_in": 1,
  "refresh_token": "string",
  "scope": "string"
}
POST

/api/{version}/customer/auth/logout

Revoke the presented refresh token, and — when all_sessions=true — its whole rotation family. Access tokens expire naturally via their short TTL. Idempotent: a missing or already-revoked token returns { "revoked": false } rather than an error.

AuthenticationAnonymousCustomer authentication endpoint — called without a customer token, since this is how one is obtained.

Responses

curl -X POST \
  'https://<your-shop-domain>/api/2026-04-01/customer/auth/logout' \
  -H 'Accept: application/json'
Response200example shape
{
  "revoked": true
}
GET

/api/{version}/customer/auth/authorize

Authorization-code step 1. Validates the client and redirect_uri against the registered allowlist, redirects an unauthenticated shopper to the hosted login (and back), enforces the email-confirmation gate, then mints a single-use PKCE code and 302s to redirect_uri?code=…&state=….

The success path has no body to schematize — it is a 302, and the result is carried in the Location query string: code (single-use, exchange it at POST token with the matching code_verifier) and state (echoed verbatim, omitted if it was not sent). Most failures are 302s too: once redirect_uri has been validated, protocol errors go back to it as error + error_description + state (RFC 6749 §4.1.2.1), and an unauthenticated or unconfirmed shopper is redirected to the hosted login instead. Only the errors that occur before the client and redirect_uri are trusted — an unknown client_id, an unregistered redirect_uri — are a 400 with a body, because redirecting them would be an open redirect.

AuthenticationAnonymousCustomer authentication endpoint — called without a customer token, since this is how one is obtained.

Query parameters

NameTypeDescription
client_id
optional
string
redirect_uri
optional
string
scope
optional
string
state
optional
string
code_challenge
optional
string
code_challenge_method
optional
string

Responses

curl -X GET \
  'https://<your-shop-domain>/api/2026-04-01/customer/auth/authorize' \
  -H 'Accept: application/json'

Schemas

CustomerLogoutResponse

Envelope returned by POST customer/auth/logout with 200. The call is idempotent: an unknown or already-revoked refresh token is a 200 with false, not an error.

  • revokedboolean

    Whether this call revoked anything. Already-issued access tokens are never revoked — they stay valid until they expire, whatever this value is.

CustomerTokenResponse

The RFC 6749 §5.1 access-token response returned by POST customer/auth/token with 200. Identical for all three grants (authorization_code, password, refresh_token) — the grant only decides how the shopper is authenticated upstream.

  • access_tokenstringnullable

    Signed JWT bearer token (~2 h). Send it as Authorization: Bearer … on customers/me/*. It is not a refresh token and cannot be exchanged.

  • token_typestringnullable

    Always Bearer.

  • expires_ininteger (int32)

    Lifetime of access_token in whole seconds from issuance. Refresh before it elapses rather than treating a 401 as the signal.

  • refresh_tokenstringnullable

    Opaque vnstcr_… refresh token (~60 d). It rotates: every refresh_token grant returns a new one and invalidates the presented one, so a client that keeps reusing the old value gets invalid_grant. Store the newest each time.

  • scopestringnullable

    The space-delimited customer/* scopes actually granted. May be narrower than requested — scopes the client is not registered for are dropped rather than rejected, so check this value.

OAuthErrorResponse

The RFC 6749 §5.2 error envelope used by POST customer/auth/token and POST customer/auth/logoutnot the { errors } shape the rest of this API returns. Codes are the RFC's: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope, access_denied. The status is 401 for invalid_client and 400 for everything else. Errors are deliberately coarse — a wrong password, an unknown user and a disabled account are all invalid_grant, so nothing here can be used to probe for accounts.

  • errorstringnullable

    The RFC 6749 error code. Always present.

  • error_descriptionstringnullable

    Human-readable detail, for developers rather than shoppers. Omitted entirely — not null — when the spine has nothing to add, so test for the key's presence.