Spree Commerce Authentication API
Admin user login, logout, token refresh, and current user profile
Admin user login, logout, token refresh, and current user profile
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/spree-authentication-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
openapi: 3.0.3
info:
title: Admin Account / Address Authentication API
contact:
name: Spree Commerce
url: https://spreecommerce.org
email: hello@spreecommerce.org
description: "Spree Admin API v3 - Administrative API for managing products, orders, and store settings.\n\n## Authentication\n\nThe Admin API requires a secret API key passed in the `x-spree-api-key` header.\nSecret API keys can be generated in the Spree admin dashboard.\n\n## Response Format\n\nAll responses are JSON. List endpoints return paginated responses with `data` and `meta` keys.\nSingle resource endpoints return a flat JSON object.\n\n## Resource IDs\n\nEvery resource is identified by an opaque string ID (e.g. `prod_86Rf07xd4z`,\n`variant_k5nR8xLq`, `or_UkLWZg9DAJ`). Use these IDs everywhere — URL paths,\nrequest bodies, and Ransack filters all accept them directly.\n\n## Error Handling\n\nErrors return a consistent format:\n```json\n{\n \"error\": {\n \"code\": \"validation_error\",\n \"message\": \"Validation failed\",\n \"details\": { \"name\": [\"can't be blank\"] }\n }\n}\n```\n"
version: v3
servers:
- url: http://{defaultHost}
variables:
defaultHost:
default: localhost:3000
tags:
- name: Authentication
description: Admin user login, logout, token refresh, and current user profile
paths:
/api/v3/admin/auth/login:
post:
summary: Login
tags:
- Authentication
security:
- api_key: []
description: 'Authenticates an admin user and returns a short-lived JWT access token.
The rotatable refresh token is set in an HttpOnly cookie — it is not
included in the response body.
Dispatches by the `provider` field to a strategy registered in
`Spree.admin_authentication_strategies`. When `provider` is omitted it
defaults to `email`, which uses the built-in email/password strategy.
To plug in a third-party identity provider (Okta, Azure AD, Google
Workspace SSO, a custom JWT issuer, SAML, etc.), register a
`Spree::Authentication::Strategies::BaseStrategy` subclass under a
provider key, then send `{ "provider": "<your_key>", ... }` with the
fields your strategy requires. The endpoint returns the same Spree-issued
JWT regardless of which strategy authenticated the request.
'
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n baseUrl: 'https://your-store.com',\n secretKey: 'sk_xxx',\n})\n\n// The refresh token is set as an HttpOnly cookie; only `token` and `user` come back in the body.\nconst auth = await client.auth.login({\n email: 'admin@example.com',\n password: 'password123',\n})"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: login successful
content:
application/json:
example:
token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJhZG1pbiIsImp0aSI6ImUyMzYxNTc5LWMxZDMtNDc0Yi1hM2E1LTcwNWMzYTZmMGUxYSIsImlzcyI6InNwcmVlIiwiYXVkIjoiYWRtaW5fYXBpIiwiZXhwIjoxNzgxMjg1MzI3fQ.5GaxxoaCeEEpGgum01ZV0z56ZpHDWaFSyX_KvEob3ws
user:
id: admin_UkLWZg9DAJ
email: admin@example.com
first_name: Lisandra
last_name: Dare
full_name: Lisandra Dare
created_at: '2026-06-12T17:23:47.304Z'
updated_at: '2026-06-12T17:23:47.304Z'
roles:
- id: role_UkLWZg9DAJ
name: admin
schema:
$ref: '#/components/schemas/AuthResponse'
'401':
description: invalid credentials
content:
application/json:
example:
error:
code: authentication_failed
message: Invalid email or password
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
content:
application/json:
schema:
oneOf:
- title: EmailPasswordLogin
description: Built-in email/password authentication (default when `provider` is omitted).
type: object
properties:
provider:
type: string
enum:
- email
default: email
email:
type: string
format: email
example: admin@example.com
password:
type: string
example: password123
required:
- email
- password
- title: ProviderLogin
description: 'Provider-dispatched login. The `provider` key selects a registered
strategy class; the remaining fields are forwarded to the strategy''s
`authenticate` method. Required fields depend on the registered strategy
— consult its documentation.
'
type: object
properties:
provider:
type: string
example: okta
description: Registered provider key (anything other than `email`).
not:
enum:
- email
required:
- provider
additionalProperties: true
/api/v3/admin/auth/refresh:
post:
summary: Refresh token
tags:
- Authentication
security:
- api_key: []
description: 'Exchanges the HttpOnly refresh-token cookie for a new access JWT and a
rotated refresh token cookie. No request body or Authorization header
is required — the cookie alone authenticates the call.
'
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n baseUrl: 'https://your-store.com',\n secretKey: 'sk_xxx',\n})\n\n// Driven entirely by the HttpOnly refresh-token cookie + CSRF header (set by the SDK).\nconst auth = await client.auth.refresh()"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: refresh successful
content:
application/json:
example:
token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJhZG1pbiIsImp0aSI6IjYxNTkwZmYyLWEwMTctNDUyZi05ZjQ3LTBhM2JhYWZlYWQ0YiIsImlzcyI6InNwcmVlIiwiYXVkIjoiYWRtaW5fYXBpIiwiZXhwIjoxNzgxMjg1MzI4fQ.l53NCGqm7_mD8L54Wq7AB86HGHqolGJEplh7Dg_QqJw
user:
id: admin_UkLWZg9DAJ
email: admin@example.com
first_name: Lavonda
last_name: Bogan
full_name: Lavonda Bogan
created_at: '2026-06-12T17:23:48.682Z'
updated_at: '2026-06-12T17:23:48.682Z'
roles:
- id: role_UkLWZg9DAJ
name: admin
schema:
$ref: '#/components/schemas/AuthResponse'
'401':
description: missing or invalid refresh-token cookie
content:
application/json:
example:
error:
code: invalid_refresh_token
message: Refresh token cookie missing
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/v3/admin/auth/logout:
post:
summary: Logout
tags:
- Authentication
security:
- api_key: []
description: Revokes the refresh-token cookie, effectively logging the admin out.
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n baseUrl: 'https://your-store.com',\n secretKey: 'sk_xxx',\n})\n\nawait client.auth.logout()"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'204':
description: logout successful
/api/v3/admin/me:
get:
summary: Get current admin user and permissions
tags:
- Authentication
security:
- api_key: []
bearer_auth: []
description: Returns the current admin user profile and a serialized list of permissions (CanCanCan rules). The SPA uses these to drive UI permission checks.
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n baseUrl: 'https://your-store.com',\n secretKey: 'sk_xxx',\n})\n\nconst me = await client.me.get()\nif (me.permissions.some((r) => r.allow && r.actions.includes('manage') && r.subjects.includes('Spree::Product'))) {\n // show \"Create product\" button\n}"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
- name: Authorization
in: header
required: true
description: Bearer token for admin authentication
schema:
type: string
responses:
'200':
description: current admin user and permissions
content:
application/json:
example:
user:
id: admin_UkLWZg9DAJ
email: loralee@bodeolson.name
first_name: Thelma
last_name: Cronin
full_name: Thelma Cronin
created_at: '2026-06-12T17:24:22.538Z'
updated_at: '2026-06-12T17:24:22.538Z'
roles:
- id: role_UkLWZg9DAJ
name: admin
permissions:
- allow: true
actions:
- manage
subjects:
- all
has_conditions: false
- allow: false
actions:
- cancel
subjects:
- Spree::Order
has_conditions: false
- allow: true
actions:
- cancel
subjects:
- Spree::Order
has_conditions: true
- allow: false
actions:
- destroy
subjects:
- Spree::Order
has_conditions: false
- allow: true
actions:
- destroy
subjects:
- Spree::Order
has_conditions: true
- allow: false
actions:
- edit
- update
subjects:
- Spree::RefundReason
has_conditions: true
- allow: false
actions:
- edit
- update
subjects:
- Spree::ReimbursementType
has_conditions: true
- allow: false
actions:
- update
- destroy
subjects:
- Spree::Role
has_conditions: true
schema:
$ref: '#/components/schemas/MeResponse'
'401':
description: unauthorized
content:
application/json:
example:
error:
code: authentication_required
message: Authentication required
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/v3/store/auth/login:
post:
summary: Login
tags:
- Authentication
security:
- api_key: []
description: 'Authenticates a customer and returns a JWT access token + refresh token.
Dispatches by the `provider` field to a strategy registered in
`Spree.store_authentication_strategies`. When `provider` is omitted it
defaults to `email`, which uses the built-in email/password strategy.
To plug in a third-party identity provider (Auth0, Okta, Firebase, a
custom JWT issuer, SAML, etc.), register a `Spree::Authentication::Strategies::BaseStrategy`
subclass under a provider key, then send `{ "provider": "<your_key>", ... }`
with the fields your strategy requires. The endpoint returns the same
Spree-issued JWT + refresh token regardless of which strategy authenticated
the request.
'
x-codeSamples:
- lang: javascript
label: Spree SDK
source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '<api-key>',\n})\n\nconst auth = await client.auth.login({\n email: 'customer@example.com',\n password: 'password123',\n})"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: login successful
content:
application/json:
example:
token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjY0NjcwM2Q0LWY5ZjAtNDlmMi05ZmZkLTA3YTZhY2I5YWZkZiIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjE1fQ.jlz2KHxYkB1Dd9ucl26zy6E5M7dFB5q9g-Qw0YjsX50
refresh_token: MQ9QZ1ToR8QocZoDd4ggC8yN
user:
id: cus_UkLWZg9DAJ
email: test@example.com
first_name: Colette
last_name: Hegmann
phone: null
accepts_email_marketing: false
full_name: Colette Hegmann
available_store_credit_total: '0'
display_available_store_credit_total: $0.00
addresses: []
default_billing_address: null
default_shipping_address: null
schema:
$ref: '#/components/schemas/AuthResponse_2'
'401':
description: missing API key
content:
application/json:
example:
error:
code: invalid_token
message: Valid API key required
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
content:
application/json:
schema:
oneOf:
- title: EmailPasswordLogin
description: Built-in email/password authentication (default when `provider` is omitted).
type: object
properties:
provider:
type: string
enum:
- email
default: email
email:
type: string
format: email
example: customer@example.com
password:
type: string
example: password123
required:
- email
- password
- title: ProviderLogin
description: 'Provider-dispatched login. The `provider` key selects a registered
strategy class; the remaining fields are forwarded to the strategy''s
`authenticate` method. Required fields depend on the registered strategy
— consult its documentation.
'
type: object
properties:
provider:
type: string
example: auth0
description: Registered provider key (anything other than `email`).
not:
enum:
- email
required:
- provider
additionalProperties: true
/api/v3/store/auth/refresh:
post:
summary: Refresh token
tags:
- Authentication
security:
- api_key: []
description: Exchanges a refresh token for a new access JWT and rotated refresh token. No Authorization header needed.
x-codeSamples:
- lang: javascript
label: Spree SDK
source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '<api-key>',\n})\n\nconst auth = await client.auth.refresh({\n refresh_token: 'rt_xxx',\n})"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: token refreshed
content:
application/json:
example:
token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjNmZjU3NWU0LTVmNmItNDVjOC04MzIzLTIzMDMyMzVjZTkzMiIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjE2fQ.OuCk-UNe-asA8DvK2yKMkp94BQz9PN_Z7_SnReeIRYE
refresh_token: qLuZDRo8LqywXFThqPM5V2Ug
user:
id: cus_UkLWZg9DAJ
email: test@example.com
first_name: Debi
last_name: Tillman
phone: null
accepts_email_marketing: false
full_name: Debi Tillman
available_store_credit_total: '0'
display_available_store_credit_total: $0.00
addresses: []
default_billing_address: null
default_shipping_address: null
schema:
$ref: '#/components/schemas/AuthResponse_2'
'401':
description: missing or invalid refresh token
content:
application/json:
example:
error:
code: invalid_refresh_token
message: Invalid or expired refresh token
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
content:
application/json:
schema:
type: object
properties:
refresh_token:
type: string
description: Refresh token from login response
required:
- refresh_token
/api/v3/store/auth/logout:
post:
summary: Logout
tags:
- Authentication
security:
- api_key: []
description: Revokes the submitted refresh token. The refresh token itself is the credential — no Authorization header is required, so a client with an expired access JWT can still log out.
x-codeSamples:
- lang: javascript
label: Spree SDK
source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '<api-key>',\n})\n\nawait client.auth.logout({\n refresh_token: 'rt_xxx',\n})"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'204':
description: logout without refresh token (no-op)
requestBody:
content:
application/json:
schema:
type: object
properties:
refresh_token:
type: string
description: Refresh token to revoke
/api/v3/store/password_resets:
post:
summary: Request a password reset
tags:
- Authentication
security:
- api_key: []
description: Sends a password reset email if an account exists for the given email address. Always returns 202 Accepted to prevent email enumeration.
x-codeSamples:
- lang: javascript
label: Spree SDK
source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '<api-key>',\n})\n\nawait client.passwordResets.create({\n email: 'customer@example.com',\n redirect_url: 'https://myshop.com/reset-password',\n})"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'202':
description: email not found (same response to prevent enumeration)
content:
application/json:
example:
message: If an account exists for that email, password reset instructions have been sent.
schema:
type: object
properties:
message:
type: string
'401':
description: missing API key
content:
application/json:
example:
error:
code: invalid_token
message: Valid API key required
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
example: customer@example.com
description: Email address of the account to reset
redirect_url:
type: string
format: uri
example: https://myshop.com/reset-password
description: URL to redirect the user to after clicking the reset link. Validated against the store's allowed origins.
required:
- email
/api/v3/store/password_resets/{token}:
patch:
summary: Reset password with token
tags:
- Authentication
security:
- api_key: []
description: Resets the password using a token received via email. Returns a JWT token on success (auto-login).
x-codeSamples:
- lang: javascript
label: Spree SDK
source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '<api-key>',\n})\n\nconst auth = await client.passwordResets.update(\n 'reset-token-from-email',\n {\n password: 'newsecurepassword',\n password_confirmation: 'newsecurepassword',\n }\n)"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
- name: token
in: path
required: true
description: Password reset token from the email
schema:
type: string
responses:
'200':
description: password reset successful
content:
application/json:
example:
token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjU1YjA5Yzc4LTUzMTYtNDRjYy05ZjJiLThmN2E2MzViMmRlNSIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjI4fQ.FX2Te4WfdAu3kN_fvvfHsH92_axvIZTI1d8Zmw8R1mE
refresh_token: Be2HUCjiJVRjgidFuYU7GRRh
user:
id: cus_UkLWZg9DAJ
email: customer@example.com
first_name: Randa
last_name: O'Hara
phone: null
accepts_email_marketing: false
full_name: Randa O'Hara
available_store_credit_total: '0'
display_available_store_credit_total: $0.00
addresses: []
default_billing_address: null
default_shipping_address: null
schema:
$ref: '#/components/schemas/AuthResponse_2'
'422':
description: password confirmation mismatch
content:
application/json:
example:
error:
code: validation_error
message: Password confirmation doesn't match Password
details:
password_confirmation:
- doesn't match Password
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: missing API key
content:
application/json:
example:
error:
code: invalid_token
message: Valid API key required
schema:
$ref: '#/components/schemas/ErrorResponse'
requestBody:
content:
application/json:
schema:
type: object
properties:
password:
type: string
minLength: 6
example: newsecurepassword
password_confirmation:
type: string
example: newsecurepassword
required:
- password
- password_confirmation
components:
schemas:
AuthResponse:
type: object
properties:
token:
type: string
description: JWT access token
user:
$ref: '#/components/schemas/AdminUser'
required:
- token
- user
AdminUserRoleAssignment:
type: object
description: A role assignment for the current store on a staff member
properties:
id:
type: string
description: Prefixed role ID
example: role_abc123
name:
type: string
description: Role name
example: admin
required:
- id
- name
AdminUser:
type: object
properties:
id:
type: string
email:
type: string
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
full_name:
type: string
nullable: true
created_at:
type: string
updated_at:
type: string
roles:
type: array
items:
$ref: '#/components/schemas/AdminUserRoleAssignment'
required:
- id
- email
- first_name
- last_name
- full_name
- created_at
- updated_at
- roles
x-typelizer: true
Customer:
type: object
properties:
id:
type: string
email:
type: string
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
phone:
type: string
nullable: true
accepts_email_marketing:
type: boolean
full_name:
type: string
available_store_credit_total:
type: string
display_available_store_credit_total:
type: string
addresses:
type: array
items:
$ref: '#/components/schemas/Address'
default_billing_address:
allOf:
- $ref: '#/components/schemas/Address'
nullable: true
default_shipping_address:
allOf:
- $ref: '#/components/schemas/Address'
nullable: true
required:
- id
- email
- first_name
- last_name
- phone
- accepts_email_marketing
- full_name
- available_store_credit_total
- display_available_store_credit_total
- addresses
- default_billing_address
- default_shipping_address
x-typelizer: true
Address:
type: object
properties:
id:
type: string
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
full_name:
type: string
address1:
type: string
nullable: true
address2:
type: string
nullable: true
postal_code:
type: string
nullable: true
city:
type: string
nullable: true
phone:
type: string
nullable: true
company:
type: string
nullable: true
country_name:
type: string
country_iso:
type: string
state_text:
type: string
nullable: true
state_abbr:
type: string
nullable: true
quick_checkout:
type: boolean
is_default_billing:
type: boolean
is_default_shipping:
type: boolean
state_name:
type: string
nullable: true
required:
- id
- first_name
- last_name
- full_name
- address1
- address2
- postal_code
- city
- phone
- company
- country_name
- country_iso
- state_text
- state_abbr
- quick_checkout
- is_default_billing
- is_default_shipping
- state_name
x-typelizer: true
PermissionRule:
type: object
description: A single permission rule (CanCanCan rule). Rules are applied in order, last-matching-wins.
properties:
allow:
type: boolean
description: true for `can`, false for `cannot`
actions:
type: array
items:
type: string
description: Action names, e.g. ["read", "update"] or ["manage"]
subjects:
type: array
items:
type: string
description: Subject class names, e.g. ["Spree::Product"] or ["all"]
has_conditions:
type: boolean
description: True if the server-side rule has per-record conditions. The SPA shows the action optimistically and handles 403 from the API.
required:
- allow
- actions
- subjects
- has_conditions
ErrorResponse:
type: object
properties:
error:
type: object
properties:
code:
type: string
example: record_not_found
message:
type: string
example: Record not found
details:
type: object
description: Field-specific validation errors
nullable: true
example:
name:
- is too short
- is required
email:
- is invalid
required:
- code
- message
required:
- error
example:
error:
code: validation_error
message: Validation failed
details:
name:
- is too short
email:
- is invalid
MeResponse:
type: object
description: Current admin user profile and serialized permissions
properties:
user:
$ref: '#/components/schemas/AdminUser'
permissions:
type: array
items:
$ref: '#/components/schemas/PermissionRule'
required:
- user
- permissions
AuthResponse_2:
type: object
properties:
token:
type: string
description: JWT access token
refresh_token:
type: string
description: Refresh token for obtaining new access tokens
user:
$ref: '#/components/schemas/Customer'
required:
- token
- refresh_token
- user
securitySchemes:
api_key:
type: apiKey
name: x-spree-api-key
in: header
description: Secret API key for admin access
bearer_auth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT token for admin user authentication
x-tagGroups:
- name: Authentication
tags:
- Authentication
- name: Produ
# --- truncated at 32 KB (32 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spree/refs/heads/main/openapi/spree-authentication-api-openapi.yml