# Sign in to the staff console

> Sign in to the staff console with your organization account, use two-factor authentication, confirm risky actions and end your sessions.

Source: https://docs.coritan.com/organizations/staff-console/sign-in/

Your team signs in to the staff console on your storefront domain, at `/staff/login`, with the email and password of their Coritan account. The sign-in gives a *console session* for one organization, which carries the member's role and works until they sign out or it expires. Set up two-factor authentication here too, and learn the check the console makes before actions that move money or end things.

## Before you begin

- You need to be a member of the organization. [Manage members and roles](/organizations/members-and-roles/) explains how an owner or admin adds you.
- If you were invited, set your password first from the invitation email. Its link opens `/staff/reset-password` on your storefront domain and works for 2 hours.
- Keep an authenticator app to hand if your organization requires two-factor authentication.

## Sign in

1. Open `/staff/login` on your storefront domain, for example `https://example.com/staff/login`.
2. Enter your email and password, and complete the challenge if the form shows one.
3. If you use two-factor authentication, enter the 6-digit code from your authenticator app. Without your phone, enter one of your recovery codes in the same field. The code step waits 5 minutes; after that, start again.
4. If your organization requires two-factor authentication and you have not set it up, the console asks you to do it now, as in [Set up two-factor authentication](#set-up-two-factor-authentication). You have 30 minutes, and the console opens once the first code is confirmed.

The same sign-in opens the storefront as your own customer account, when you have one. [Change a member's storefront account](/organizations/members-and-roles/#change-a-member-s-storefront-account) says which account that is.

## Set up two-factor authentication

With two-factor authentication on, you sign in with your password and a code from an authenticator app.

1. Open the My account page, `/staff/me`.
2. Start the setup, then scan the QR code with your authenticator app, or type in the secret it shows.
3. Enter the 6-digit code from the app to turn two-factor authentication on.
4. Save the 10 recovery codes. The console shows them once, and each one signs you in once when your phone is not to hand.

> [!IMPORTANT]
> Keep the recovery codes somewhere other than your phone. Without the app and without a code, only an admin can reset your second factor, and the owner's cannot be reset from the console at all.

To make new recovery codes, enter a current code; the old set stops working at once. To turn two-factor authentication off, enter your password and a current code. You cannot turn it off while your organization requires it of every member: ask an admin to reset it, then set it up again.

## Confirm it is you

Some actions ask you to confirm it is you, even though you are signed in. This check is a *step-up*: enter a code from your authenticator, or your password if you have no two-factor authentication. It lasts 10 minutes, and signing in counts as one, so the first 10 minutes after you sign in need no extra check.

These actions ask for it:

- Customers: adding or taking away credit, resetting a password or second factor, changing an account's status, closing an account, exporting its data, and opening a support session that can make changes.
- Billing: charging, refunding or marking an invoice paid, deciding a refund request and terminating a service.
- Servers: restoring or deleting a backup or snapshot, deleting a database or reading its password, and changing the startup settings.
- Bulk actions that terminate, ban or schedule a deletion, on customers or on servers.
- The team: changing a role, removing a member, resetting their password or second factor, and changing their storefront account.

Only a console session has a step-up. A coritan.com access token reaches the same staff routes, but these actions refuse it, so do them signed in to the console.

## Reset a forgotten password

1. Follow the forgotten password link on the sign-in page, which opens `/staff/forgot-password`, and enter your email.
2. Open the link in the email within 2 hours. It opens `/staff/reset-password` on your storefront domain.
3. Enter a new password. It needs 8 to 128 characters, with a lowercase letter, an uppercase letter, a digit and a special character.

Setting the password signs you out of every console session, so sign in again with it.

## Sign out and end sessions

Signing out ends the console session and every storefront session it opened for you. To end a session on another device, open the My account page, find the session in the list and end it, or end every session but the one you are using.

## Result

You are in the console with your role, and the pages you see are the ones that role can use. [Organization roles and permissions](/organizations/roles-and-permissions/#the-staff-console) lists them.

## Troubleshooting

`Invalid credentials`
: The email is not a member of this organization, or the password is wrong. The answer is the same for both.

`Set a password from the invite email before signing in`
: You were invited and have not set a password yet. Follow the invitation link, or ask an admin for a new one.

`Account is suspended or closed`
: Your Coritan account cannot sign in. Contact Coritan support.

`That code is not right`
: The code has expired or was mistyped. Codes change every 30 seconds, so check that your phone's clock is correct.

`Finish signing in with your second factor`
: A session waiting for its code was used on another route. Enter the code first.

`Confirm your password or a code from your authenticator to do this.`
: The action needs a step-up and your last one is more than 10 minutes old. Confirm and try again.

`This brand requires two-factor for staff; ask an admin to reset yours instead`
: You tried to turn two-factor authentication off while your organization requires it.

`Too many requests for this action. Please wait and try again.`
: You tried 10 codes, or 10 step-ups, in 5 minutes. Wait a few minutes before you try again.

## Related

- [The staff console](/organizations/staff-console/)
- [Manage the staff team and console settings](/organizations/staff-console/team-and-settings/)
- [Manage members and roles](/organizations/members-and-roles/)

## With the API

The console is built on these routes, under `https://api.coritan.com/api/v1/orgs/{org_slug}/staff/auth/`. The reference lists them all under [Customer Authentication: staff](/api/reference/organizations/customer-authentication/staff/).

### Sign in with a password and a code

Send the email and password. When your brand has a Turnstile challenge on its forms, `turnstile_token` is the answer from that widget, and without it the sign-in answers `403` with `turnstile_failed`, so a script cannot sign in on its own there.

```bash
curl -X POST https://api.coritan.com/api/v1/orgs/acme/staff/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "alex@example.com", "password": "your-password", "turnstile_token": "the-widget-answer"}'
```

A member without two-factor authentication gets the session at once:

```json
{
  "access_token": "ost_...",
  "refresh_token": "ost_...",
  "expires_in": 86400,
  "token_type": "bearer",
  "role": "support_tier2",
  "mfa_required": false,
  "mfa_setup_required": false,
  "staff": {"id": 14, "email": "alex@example.com", "role": "support_tier2"},
  "customer_session": {"access_token": "...", "refresh_token": "...", "customer_id": 812, "customer_email": "alex@example.com"}
}
```

`customer_session` is a storefront session for the member's own customer account, or `null` when they have none. A member with two-factor authentication gets `"mfa_required": true` and an `mfa_token` that lasts 300 seconds instead. Send it with the code:

```bash
curl -X POST https://api.coritan.com/api/v1/orgs/acme/staff/auth/mfa/verify \
  -H "Authorization: Bearer $MFA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"code": "492817"}'
```

The answer is the same session, plus `how` (`totp`, or `recovery` for a recovery code) and `recovery_codes_left`. When the organization requires two-factor authentication of a member who has none, the sign-in answers `"mfa_setup_required": true` with an `mfa_token` that lasts 1800 seconds: use it for the enrolment below, and `enable` answers with the session under `tokens`.

### Use and refresh the session

Send the access token as a Bearer token on every staff route. It lasts 24 hours. Before it expires, trade the refresh token, which lasts 30 days, for a new pair; the old pair stops working.

```bash
curl https://api.coritan.com/api/v1/orgs/acme/staff/auth/me \
  -H "Authorization: Bearer $STAFF_TOKEN"

curl -X POST https://api.coritan.com/api/v1/orgs/acme/staff/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "ost_..."}'
```

`GET me` answers the member with their `role`, `email` and `name`, plus `org_requires_mfa`, `reauthed_at` (the last step-up) and the storefront account in `customer_id` and `customer_link`. A refreshed session has no step-up until you make one. `PATCH me` with `{"name": "Alex Example"}` changes your name.

`POST /staff/auth/customer-session` gives a new storefront session for your own customer account. It answers `409 You have no active customer account on this brand` when you have none.

### Step up

```bash
curl -X POST https://api.coritan.com/api/v1/orgs/acme/staff/auth/reauth \
  -H "Authorization: Bearer $STAFF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"code": "492817"}'
```

Send `code` when two-factor authentication is on, and `password` when it is off. The answer is `{"ok": true, "reauthed_at": "...", "how": "totp", "max_age_seconds": 600}`. An action that needs a step-up and has none answers:

```json
{"detail": {"error": "reauth_required", "message": "Confirm your password or a code from your authenticator to do this.", "max_age_seconds": 600}}
```

with status `403`. Each member may try 10 codes in 5 minutes, and make 10 step-ups in 5 minutes.

### Turn on two-factor authentication

1. `POST /staff/auth/mfa/setup` answers `secret`, `otpauth_uri` and `qr_svg` for the authenticator app.
2. `POST /staff/auth/mfa/enable` with `{"code": "492817"}` turns it on and answers the 10 `recovery_codes`, once.

`GET /staff/auth/mfa` answers `enabled`, `recovery_codes_left` and `org_requires_mfa`. `POST /staff/auth/mfa/recovery-codes` with a current `code` makes a new set, and `POST /staff/auth/mfa/disable` with `password` and `code` turns it off.

### Passwords and sessions

| Route | What it does |
| --- | --- |
| `POST /staff/auth/forgot-password` | Emails a reset link to `email`. It answers `{"ok": true}` whether or not the email is a member, and takes `turnstile_token` as the sign-in does. |
| `POST /staff/auth/reset-password` | Sets `password` from the email's `token`, and ends every console session of the member. |
| `POST /staff/auth/change-password` | Sets `new_password` after checking `current_password`, and ends your other sessions. It answers `sessions_ended`. |
| `GET /staff/auth/sessions` | Your live sessions, newest first and at most 50, each with `id`, `created_at`, `expires_at`, `ip_address`, `user_agent` and `is_current`. |
| `DELETE /staff/auth/sessions/{token_id}` | Ends one of your sessions. |
| `POST /staff/auth/sessions/revoke-others` | Ends every session but this one, and answers how many in `revoked`. |
| `POST /staff/auth/logout` | Ends this session and the storefront sessions it opened. |

## API

- `POST /api/v1/orgs/{org_slug}/staff/auth/change-password`: Change your own password (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-change-password)
- `POST /api/v1/orgs/{org_slug}/staff/auth/customer-session`: A fresh storefront session for the member's own customer account (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-customer-session)
- `POST /api/v1/orgs/{org_slug}/staff/auth/forgot-password`: Staff forgot password (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-forgot-password)
- `POST /api/v1/orgs/{org_slug}/staff/auth/login`: Staff login (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-login)
- `POST /api/v1/orgs/{org_slug}/staff/auth/logout`: Staff logout (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-logout)
- `GET /api/v1/orgs/{org_slug}/staff/auth/me`: Staff me (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-get-api-v1-orgs-org-slug-staff-auth-me)
- `PATCH /api/v1/orgs/{org_slug}/staff/auth/me`: Staff patch me (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-patch-api-v1-orgs-org-slug-staff-auth-me)
- `GET /api/v1/orgs/{org_slug}/staff/auth/mfa`: Staff MFA status (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-get-api-v1-orgs-org-slug-staff-auth-mfa)
- `POST /api/v1/orgs/{org_slug}/staff/auth/mfa/disable`: Turn the factor off: password and a current code, both (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-mfa-disable)
- `POST /api/v1/orgs/{org_slug}/staff/auth/mfa/enable`: Confirm the code from the freshly scanned secret (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-mfa-enable)
- `POST /api/v1/orgs/{org_slug}/staff/auth/mfa/recovery-codes`: A new set of recovery codes against a current code; the old set is void (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-mfa-recovery-codes)
- `POST /api/v1/orgs/{org_slug}/staff/auth/mfa/setup`: Start (or restart) enrolment: a fresh secret, the otpauth URI and the QR code for it (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-mfa-setup)
- `POST /api/v1/orgs/{org_slug}/staff/auth/mfa/verify`: The second step of signing in (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-mfa-verify)
- `POST /api/v1/orgs/{org_slug}/staff/auth/reauth`: Prove it is still you (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-reauth)
- `POST /api/v1/orgs/{org_slug}/staff/auth/refresh`: Staff refresh (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-refresh)
- `POST /api/v1/orgs/{org_slug}/staff/auth/reset-password`: Staff reset password (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-reset-password)
- `GET /api/v1/orgs/{org_slug}/staff/auth/sessions`: Staff my sessions (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-get-api-v1-orgs-org-slug-staff-auth-sessions)
- `POST /api/v1/orgs/{org_slug}/staff/auth/sessions/revoke-others`: Staff end other sessions (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-post-api-v1-orgs-org-slug-staff-auth-sessions-revoke-others)
- `DELETE /api/v1/orgs/{org_slug}/staff/auth/sessions/{token_id}`: Staff end my session (https://docs.coritan.com/api/reference/organizations/customer-authentication/staff/#op-delete-api-v1-orgs-org-slug-staff-auth-sessions-token-id)
