Skip to content
Coritan Docs

Sign customers in to your storefront

Register, sign in and verify your customers, refresh their tokens, and add two-factor authentication and social sign-in.

View as Markdown

Your customers have accounts with your organization, separate from Coritan accounts. Your storefront creates them and signs them in through /auth/..., and gets back a customer token that every /portal/... call takes as Authorization: Bearer.

  • Choose how your organization's email leaves under Outgoing email (SMTP) in Settings. We send your customers welcome, verification and password reset emails. See Change organization settings.
  • Set your Custom domain in the same place. Emails link to pages on it, which your storefront must serve: /verify-email?id=...&token=..., /reset-password?token=... and /billing/invoices/{invoice_id}. Social sign-in returns to /auth/callback.
  • If GET /storefront/branding reports turnstile.enabled, show the Cloudflare Turnstile challenge on your sign-up form and send its answer with the request.
Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/auth/register" \
  -H "Content-Type: application/json" \
  -d '{"email": "alex@example.com", "password": "a long passphrase", "username": "alex_builds", "first_name": "Alex", "turnstile_token": "..."}'

email and password are required, and the password needs at least 8 characters. username, first_name, last_name, company and phone are optional. Without a username we generate one. GET /auth/username-available?username=... says whether a name is free, and why not in reason, while the customer types.

A username has 3–20 letters, digits and underscores. Names that pass for staff, and names our moderation filter refuses, are not available. A customer can change theirs once every 7 days.

The answer is 201 with the customer's tokens, as for signing in. We also send your welcome email and an email to confirm the address, and your webhooks receive customer.created. Confirming the address is optional: nothing on the account waits for it.

Shell
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "alex@example.com", "password": "a long passphrase"}'

identifier takes an email address or a username. The answer is one of two shapes:

  • A session: access_token, refresh_token, token_type and expires_in. The access token lasts 24 hours and the refresh token 30 days.
  • A two-factor step: mfa_token with mfa_required: true when the customer has two-factor authentication on, or mfa_setup_required: true when your organization requires it and the customer has not set it up. Continue under Two-factor authentication.

Only active customers can sign in. A customer who registered with a social account has no password until they set one.

  • Before the access token expires, send {"refresh_token": "..."} to POST /auth/refresh. The answer is a new pair, and the old tokens stop working at once.
  • POST /auth/logout signs out the session whose token it carries.
  • GET /auth/sessions lists where the customer is signed in, with the address, country, browser and expiry of each. current marks the one asking, and support_session marks a session your staff opened to look at the account.
  • POST /auth/sessions/revoke-others signs out every other session and answers with how many it ended.

GET /auth/me returns the customer's profile. PATCH /auth/me changes first_name, last_name, company, phone or chat_handle (the username). To change the password, send password with current_password.

Customers turn on two-factor authentication with an authenticator app. To require it of every customer, turn it on in your staff console's settings. See Manage the staff team and console settings.

  1. POST /auth/mfa/setup returns a secret, an otpauth_uri and a qr_svg to show.
  2. The customer scans it and sends a code to POST /auth/mfa/enable as {"code": "123456"}. The answer holds 10 recovery_codes, shown once. When the request carried an mfa_token, it also holds the session in tokens.
  3. From then on, signing in answers with an mfa_token. Send it as the bearer token to POST /auth/mfa/verify with a code from the app or a recovery code, and the answer is the session.

An mfa_token works only on the /auth/mfa routes. It lasts 5 minutes for a sign-in, and 30 minutes for setting up when your organization requires two-factor authentication.

GET /auth/mfa says whether it is on and how many recovery codes are left. POST /auth/mfa/recovery-codes replaces the codes, given a current code. POST /auth/mfa/disable turns it off, given a code and the password when the account has one. It is refused while your organization requires two-factor authentication; your staff can reset a customer's instead.

Coritan configures the providers. GET /auth/oauth/providers lists the ones your storefront can offer, from discord, github, google and microsoft.

  1. Call GET /auth/oauth/{provider}/authorize and send the customer to the authorization_url it returns.
  2. After the provider, we send the customer back to /auth/callback on your storefront with the result in the URL fragment: access_token, refresh_token and expires_in, or mfa_token and its flags, or error. new_account=true marks a customer we just registered.

We return the customer only to a storefront address that Coritan has registered for your organization. Contact support to register yours before you offer social sign-in.

A signed-in customer can link another provider by calling authorize with their token. When a provider's email matches an existing customer, we refuse with account_exists_login_required: the customer signs in with their password, then links the provider. GET /auth/oauth/connections lists the linked providers, and DELETE /auth/oauth/connections/{provider} removes one. POST /auth/oauth/set-password gives a social-only account a password: 8–128 characters with a lowercase letter, an uppercase letter, a digit and a symbol.

Verify an address and reset a password

Section titled Verify an address and reset a password
  • The confirmation email links to /verify-email?id=...&token=.... Post both values to POST /auth/verify-email as customer_id and token. A link works for 24 hours, and only the newest one works. POST /auth/resend-verification sends another; sent: false with email_unavailable means your organization cannot send email.
  • POST /auth/forgot-password with email sends a reset link to /reset-password?token=.... The answer is the same whether or not the account exists. Post the token and the new password to POST /auth/reset-password within 2 hours. The reset signs the customer out everywhere.

The customer has a session your storefront keeps in the browser and sends to every /portal/... call. The customer appears on the Customers tab.

401 Invalid credentials
The identifier or the password is wrong, or the customer is not active.
401 This account uses social login ...
The customer registered with a social account. They sign in with it, or set a password from their account.
409 Email already registered or 409 That username is already taken.
Sign the customer in instead, or choose another username.
403 This email address cannot be used to register.
Your staff banned an account with that address.
403 Customer limit reached (100/100)
Your organization holds as many customers as it may. Ask support to raise the limit.
401 Invalid refresh token or 401 Refresh token expired
The refresh token was already used, revoked or is older than 30 days. Sign the customer in again.
401 with mfa_required
The token is still waiting for the second factor. Finish with POST /auth/mfa/verify.
403 Account is suspended or closed or 403 We have closed this account.
Your staff suspended, closed or banned the customer.
400 Invalid reset token or 400 Reset token expired
The link is wrong, was replaced by a newer one, or is more than 2 hours old. Ask for a new one.

API operations on this page

MethodPathWhat it does
POST/api/v1/orgs/{org_slug}/auth/forgot-passwordIssue a password-reset token stored on the customer metadata
POST/api/v1/orgs/{org_slug}/auth/loginPassword sign-in with an email address or a username
POST/api/v1/orgs/{org_slug}/auth/logoutRevoke the current access token (and its refresh twin if present)
GET/api/v1/orgs/{org_slug}/auth/meCustomer profile
PATCH/api/v1/orgs/{org_slug}/auth/meUpdate customer profile
GET/api/v1/orgs/{org_slug}/auth/mfaCustomer MFA status
POST/api/v1/orgs/{org_slug}/auth/mfa/disableTurn the factor off with a current code, and with the password when the account has one
POST/api/v1/orgs/{org_slug}/auth/mfa/enableCustomer MFA enable
POST/api/v1/orgs/{org_slug}/auth/mfa/recovery-codesCustomer MFA regenerate recovery codes
POST/api/v1/orgs/{org_slug}/auth/mfa/setupCustomer MFA setup
POST/api/v1/orgs/{org_slug}/auth/mfa/verifyCustomer MFA verify
GET/api/v1/orgs/{org_slug}/auth/oauth/connectionsList OAuth connections
DELETE/api/v1/orgs/{org_slug}/auth/oauth/connections/{provider}Disconnect OAuth provider
GET/api/v1/orgs/{org_slug}/auth/oauth/providersPublic: which social providers are configured for storefront login
POST/api/v1/orgs/{org_slug}/auth/oauth/set-passwordOAuth set password
GET/api/v1/orgs/{org_slug}/auth/oauth/{provider}/authorizeOAuth authorize
GET/api/v1/orgs/{org_slug}/auth/oauth/{provider}/callbackOAuth callback
POST/api/v1/orgs/{org_slug}/auth/refreshCustomer refresh token
POST/api/v1/orgs/{org_slug}/auth/registerSelf-service customer signup for the org storefront
POST/api/v1/orgs/{org_slug}/auth/resend-verificationSend another confirmation link to the signed-in customer's own address
POST/api/v1/orgs/{org_slug}/auth/reset-passwordCustomer reset password
GET/api/v1/orgs/{org_slug}/auth/sessionsWhere this account is currently signed in
POST/api/v1/orgs/{org_slug}/auth/sessions/revoke-othersSign out everywhere except here
GET/api/v1/orgs/{org_slug}/auth/username-availableWhether a username can be taken at signup, and why not when it cannot
POST/api/v1/orgs/{org_slug}/auth/verify-emailConfirm an address from an emailed link