Skip to content
Coritan Docs

Authentication

Which credential each part of the Coritan API accepts, how to get and refresh an access token, and how a script uses an account API key.

View as Markdown

Each route of the Coritan API takes one kind of credential, and the part of the API it belongs to decides which. This page lists each credential, the header it goes in, how you get it and how long it lasts. A few routes take none, such as GET /auth/turnstile and the list of locations.

Credentials by part of the API

Section titled Credentials by part of the API
Part of the API Paths Credential Header
Client API /api/v1/..., except the paths below Your access token, or an account API key on the routes a key may reach Authorization: Bearer <token> or Authorization: Bearer <key>
Organization API /api/v1/orgs/{org_slug}/... A member's access token, or a staff console token Authorization: Bearer <token>
Customer portal and storefront checkout /api/v1/orgs/{org_slug}/portal/..., and the storefront's order and checkout routes A customer token Authorization: Bearer <token>
Commerce API /api/v1/orgs/{org_slug}/commerce/... A member's access token or staff console token, or an organization API key Authorization: Bearer <token> or X-API-Key: <key>
Store API /api/v1/orgs/{org_slug}/store/... The store's publishable key, plus a customer token on the routes for a signed-in shopper x-publishable-api-key: <key>, and Authorization: Bearer <token>
SMTP Relay send API /api/v1/mail/send and /api/v1/mail/send/limits A send API key X-Api-Key: <key>

Access and refresh tokens, Account API keys, Organization credentials and Other keys describe each credential.

Sign in with POST /auth/login, sending email and password as JSON. Make your first API request walks through it with curl. The answer holds access_token, refresh_token, token_type (bearer) and expires_in.

Access token
Proves who you are on every Client API request, and on the Organization API for each organization you are a member of. It lasts 30 minutes unless Coritan changes the setting, and expires_in gives its lifetime in seconds.
Refresh token
Gets a new pair from POST /auth/refresh with the body {"refresh_token": "..."}, with no password, verification check or second factor. It lasts 30 days unless Coritan changes the setting. Each new pair holds a refresh token with a full lifetime, and the one you sent stops working. Sending it again more than a minute later signs the session out, so keep the new refresh token each time.
Pending token
What the sign-in answers when two-factor authentication is on: mfa_required: true and an mfa_token that lasts 10 minutes (expires_in: 600). Send it as the bearer token to POST /auth/mfa/verify with {"code": "123456"}, and the answer holds the access and refresh tokens. Every other route refuses it with 401 and "error": "mfa_required".

Changing or resetting the password stops every token issued before it, and a suspended or closed account cannot use any token. POST /auth/logout signs out the session of the access token you send as the bearer, or of the refresh token in the body {"refresh_token": "..."}. Sign out and end sessions explains how to stop a token working.

An account API key lets a script call the Client API as you, without your password or a second factor. Create one on the API keys tab of Settings. It starts with ct_, and Coritan shows it only once. Send it in the header an access token uses:

Shell
curl -s "https://api.coritan.com/api/v1/services/?limit=5" \
  -H "Authorization: Bearer $CORITAN_TOKEN"
  • A key with any Write permission can make every change you can, whatever area the permission names.
  • A key with only Read permissions can send GET and HEAD requests, and POST /checkout/quote, which prices an order without placing it. Any other request answers 403 with "code": "api_key_read_only".
  • A key with an IP allow-list works only from the addresses on it.
  • No key can reach your profile and sign-in settings (/api/v1/auth/...), your team, webmail or your organizations (/api/v1/orgs/...). No key can act for another account with the X-Coritan-Account header either. What no key can do lists the routes.
  • A WebSocket, such as a server's live console, takes an access token.

A key works until you revoke it, and changing your password leaves it working. A suspended or closed account cannot use its keys. Manage API keys covers creating, limiting and revoking keys, and Authentication errors lists the refusals.

Member access token
The same access token as the Client API. It reaches an organization's routes when you are its owner or a member, and your role decides what it may do. Without membership, a route answers 403 Not a member of this organization.
Staff console token
A console session for one organization, from POST /orgs/{org_slug}/staff/auth/login with your Coritan email and password. Its tokens start with ost_. The access token lasts 24 hours, and POST /orgs/{org_slug}/staff/auth/refresh swaps the refresh token, which lasts 30 days, for a new pair. It reaches every route a member's access token reaches. The actions that move money or end things also need a step-up in the last 10 minutes, which only a console session has: Confirm it is you lists them.
Customer token
A customer of an organization's storefront, from POST /orgs/{org_slug}/auth/login. The access token lasts 24 hours and the refresh token 30 days, and POST /orgs/{org_slug}/auth/refresh swaps them for a new pair. Sign in your storefront's customers has the details. A customer token never reaches the routes for members.
Organization API key
Lets your own systems call the Commerce API without a person signing in. An owner or admin creates it with POST /orgs/{org_slug}/api-keys; it starts with ct_, and the answer shows it once. Its scopes decide which routes it reaches, it has an hourly request limit (4,000 by default), and it can have a list of addresses it may be used from. No route outside the Commerce API reads it. Create organization API keys lists the scopes.
Publishable key
Names a store to the Store API, which serves shoppers, so the key can sit in your storefront's code. Create one with POST /orgs/{org_slug}/commerce/publishable-keys. A test key starts with pk_test_. A live key starts with pk_live_, and works once the store is live.
Send API key
Sends mail through one SMTP Relay service over HTTPS, and does nothing else. Create it on the relay, as Manage send API keys shows; it starts with mk_. The send API reads it from X-Api-Key only, never from Authorization. Send email over HTTPS has the requests.

Coritan can put a verification check on the forms that sign people in or give something away for free. GET /auth/turnstile says whether it is on:

JSON
{"enabled": true, "site_key": "..."}

An answer like that one is a Cloudflare Turnstile check. When Coritan's own check, Wicket, draws it instead, the answer also names Wicket and gives the address of its script:

JSON
{"enabled": true, "site_key": "wk_...", "provider": "wicket", "script_url": "https://wicket.coritan.com/v1/api.js?render=explicit"}

Either way the token goes in turnstile_token. While the check is on, these routes also need a turnstile_token in the body. Only the check on a web page makes one, so a script cannot sign in with a password while the check is on.

API Routes
Client API POST /auth/login, POST /auth/register, POST /auth/forgot-password, POST /auth/reset-password, and POST /services/order for a plan that costs nothing
Organization API POST /orgs/{org_slug}/auth/register, POST /orgs/{org_slug}/staff/auth/login, POST /orgs/{org_slug}/staff/auth/forgot-password, and a storefront order for a plan that costs nothing

Without a token, or with one that did not pass, the route answers 403 with {"detail": {"error": "turnstile_failed", "message": "Verification required"}}. The message is Verification failed for a token that did not pass.

Status detail Meaning
403 Not authenticated A Client API route got no Authorization header.
403 Invalid authentication credentials The Authorization header does not start with Bearer.
401 Invalid or expired token The token is not one Coritan issued, or it has expired. Refresh it, or sign in again. An account API key gets it when the key is wrong or revoked.
401 Invalid token type A refresh token was sent where an access token belongs.
401 Invalid refresh token POST /auth/refresh was sent a token that is not a refresh token.
401 {"error": "mfa_required", ...} A pending token was sent to a route other than the two-factor routes. Finish the sign-in first.
401 Token invalidated by password change The password changed after the token was issued. Sign in again.
403 Account is suspended or closed The account cannot sign in, use a token or use an API key.
403 {"code": "api_key_read_only", ...} The account API key has only Read permissions, and the request would make a change.
403 {"code": "api_key_no_permissions", ...} The account API key has no permissions, so it cannot make any request.
403 {"code": "api_key_route_refused", ...} No account API key can reach this route. The message says what to use instead.
403 {"code": "api_key_act_for_refused", ...} The request sent an account API key with the X-Coritan-Account header. A key works only on its own account.
403 {"code": "api_key_address_refused", ...} The request came from an address outside the account API key's IP allow-list. The message names the address.
401 Missing bearer token An Organization API route got no Authorization: Bearer header.
403 Not a member of this organization The token is valid, but you are not a member of that organization.
404 Organization not found No active organization has that slug. With an organization API key, the slug is not the key's organization.
401 Token expired A staff console token has expired. Refresh it.
403 {"error": "reauth_required", ...} The action needs a step-up, and the last one was more than 10 minutes ago.
401 Invalid API key A Commerce API request sent an X-API-Key that is wrong or revoked.
403 API key is not allowed from this address The request came from an address outside the organization API key's allow-list.
403 Organization inactive The organization API key's organization is not active.
403 {"error": "scope_required", ...} The organization API key lacks the scope the route needs. The message names it.
401 {"error": "publishable_key_required", ...} A Store API request had no x-publishable-api-key header.
401 {"error": "invalid_publishable_key", ...} The publishable key is wrong, revoked, or belongs to another store.
401 X-Api-Key header required A send API request had no X-Api-Key header.

Errors describes the shapes of detail, and Rate limits the 429 that too many failed sign-ins bring.

API operations on this page

MethodPathWhat it does
POST/api/v1/auth/loginLogin
POST/api/v1/auth/refreshA new token pair for a refresh token, which is then used up (app/domains/auth/sessions.py)
POST/api/v1/auth/logoutSign this device out on the server
GET/api/v1/auth/turnstileTurnstile config