Sign-in, SSO & API keys
Two-factor and MFA enforcement, session controls, SAML SSO, SCIM provisioning, API keys and service accounts, and OAuth apps.
These controls decide how people and machines sign in to a Kortix account. Every member uses them to secure their own sign-in and create keys. Owners and admins use them to set account rules, connect an identity provider, and issue keys for CI and apps. Each control also has an API route. See the REST API.
Open your own settings from the project menu → Settings. Open the account’s settings from the project menu → Switch Project → Account settings. Each control is in one of these places:
| Place | Who | What is there |
|---|---|---|
| Settings → Security | Each person, for themselves | Two-factor authentication, signed-in devices |
| Settings → Personal access keys | Each person, for themselves | Keys that act as you, connected apps |
| Account settings → Settings → Security | Owners and admins | Require two-factor authentication, Maximum session length, Idle timeout, Active sessions, Admins can open every session (Sessions) |
| Account settings → API keys | Owners and admins | Service accounts, OAuth apps, Key rules |
| Account settings → Identity | Owners and admins | SAML SSO, Directory Sync (SCIM) |
The account sections need the account.write permission, which the owner and admin
roles hold. Roles, members, and groups are on Accounts & access.
Two-factor and MFA enforcement
Turn on two-factor for yourself
- Open Settings → Security.
- Select Add authenticator app.
- Scan the QR code with any authenticator app (TOTP), or enter the key under Can’t scan? Enter this key.
- Type the 6-digit code. It verifies when you type the sixth digit.
Kortix then asks for a code at sign-in and before sensitive changes: removing a factor and signing out devices. Remove a factor from the same page.
Require two-factor for the account
- Open Account settings → Settings → Security.
- Turn on Require two-factor authentication.
- Read the preview. It counts the members with a verified factor and lists every member who has none.
- Select Require it.
When the requirement is on, a browser sign-in without a verified second factor
gets 403 with code: "account_mfa_required" on every protected action. The web
app opens a code prompt. A member with no factor enrolls one under
Settings → Security first.
- Exempt: super-admins, personal access keys, and service account keys. A key has no second factor to prompt for.
- Lockout guard: Kortix refuses to turn the requirement on when no
super-admin exists and no member has a verified factor (
409). - Turn it off: select Stop requiring it. Members can then sign in with a password alone.
Session controls
Session policy
Open Account settings → Settings → Security and set two limits, in minutes. Empty means no limit.
| Setting | Effect | Limit |
|---|---|---|
| Maximum session length | How long a browser sign-in lasts before the member signs in again | 1 to 10,080 (7 days) |
| Idle timeout | Signs a member out after this many minutes with no request | 1 to 10,080 (7 days) |
A sign-in past either limit gets 401 on its next request to the account. The
member signs in again. Keys are exempt.
Sign a member out
Active sessions, under the policy, lists the 200 most recently active browser
sign-ins in the account. Select Sign out on a row. That sign-in gets 401 on
its next request, and the member can sign in again. This needs the
member.remove permission.
Your own devices
Settings → Security → Devices lists every browser, desktop, and mobile sign-in of yours.
- Sign out on one device ends that sign-in. You cannot sign out the current device from this list. Sign out normally instead.
- Sign out other devices ends every sign-in except this browser.
Single sign-on (SAML)
SAML SSO lets members sign in with your identity provider (IdP). It needs the
sso entitlement (see Enterprise features) and an
organization account. A personal account gets 403
code: "sso_personal_account". The account Kortix creates at sign-up is
personal. Create an organization account with the project menu → Switch
Project → Create an account…, and create the team’s projects there. A
project cannot move between accounts. An account has one SSO provider.
Set it up
Open the guided setup
Open Account settings → Identity. On the SAML SSO card, select Configure and pick your IdP: Microsoft Entra ID, Okta, Google Workspace, Cloudflare Access, OneLogin, JumpCloud, PingOne, Auth0, or a custom SAML provider. The wizard shows each click in that IdP’s console.
Register Kortix in your IdP
Create a SAML app in your IdP. Copy the two values from Service provider details: Identifier (Entity ID) and Reply URL (ACS). Assign the people who may sign in.
Import the IdP metadata
Paste the IdP’s metadata URL or its metadata XML. Enter the Primary email domain and the Group claim name: the SAML attribute that carries group membership.
Verify the domain
Publish the TXT record the card shows, then select Verify domain.
Map groups
Add group mappings, or turn on Auto-provision groups. See Groups from the IdP.
Enforce SSO
Turn on Enforce SSO for this domain when every member can sign in through the IdP.
From then on, a person who enters a work email on the sign-in page goes to the IdP. With Auto-create members on (the default), Kortix adds them to the account on their first SSO sign-in.
| Setting | Default | Effect |
|---|---|---|
| Group claim name | groups |
The SAML attribute Kortix reads groups from. Okta sends group names on groups. Entra sends group object IDs by default. The Entra guide names the claim memberOf, so set Group claim name to memberOf for Entra. |
| Auto-create members | On | Adds every person who signs in through the IdP as a member. Off: SSO adds only existing members and people your SCIM directory provisioned. |
| Auto-provision groups | Off | Creates a Kortix group for every group the IdP sends, and adds the person to it. |
| Enforce SSO for this domain | Off | Refuses every other way to sign in for the primary domain. |
Verify the domain
The IdP asserts each person’s email address. Kortix trusts that address only for a domain your account verified with DNS.
| Record | Name | Value |
|---|---|---|
TXT |
_kortix-verification.<your-domain> |
kortix-verification=<token> |
DNS changes can take a few minutes to appear.
- One domain belongs to one account. A domain that another account verified
returns
409code: "sso_domain_claimed". - A new primary domain starts a new, unverified claim with a new token.
- Until the domain is verified, members still join through SSO and get their groups. Their SSO identity matches no invitation from another account, no existing identity merges into it, and Enforce SSO has no effect.
- With a verified domain, an existing member with the same email merges into the SSO identity and keeps their roles. Kortix never merges an owner or a super-admin. Their SSO sign-in joins as a separate member.
Enforce SSO
With a verified domain and Enforce SSO for this domain on, every identity in
that domain that did not come from your IdP is refused with 403:
- password sign-in, magic links, and email codes, in the web app and on the
headless sign-in routes (
/v1/auth/signup,/v1/auth/sign-in/password,/v1/auth/sign-in/magic-link,/v1/auth/verify-otp). There the body iserror: "sso_required". - the existing sessions and keys of those identities, owners and super-admins
included. Their account and project requests get
code: "sso_required".
Groups from the IdP
Kortix syncs groups on every SSO sign-in:
- It adds the person to each group a claim value maps to.
- It removes the person from a mapped group when the IdP stops sending its claim value.
- It keeps groups an admin added by hand. Only mapped groups change.
Add a mapping on the SAML SSO card under Group mappings: a Claim value and an IAM group. The match ignores case and surrounding spaces. Map Entra object IDs, or Okta group names, exactly as the IdP sends them. Give each group its project roles under Groups.
Remove SSO
Select Remove SSO provider on the SAML SSO card. Existing members keep their access. New SSO sign-ins stop joining the account, and group sync stops.
SCIM provisioning
SCIM lets your IdP create, update, and remove members and groups without a
sign-in. It needs the scim entitlement. Connect SAML SSO first: SCIM creates
members, and SSO is how they sign in.
Connect your IdP
- Open Account settings → Identity. On the Directory Sync card, select Guided setup and pick your IdP: Microsoft Entra ID, Okta, OneLogin, JumpCloud, PingOne, or any SCIM 2.0 provider.
- Mint a token. Kortix shows the secret (
kortix_scim_…) once. - In the IdP, enter the SCIM base URL and the token as a bearer token.
- Start provisioning in the IdP.
| Value | What to enter |
|---|---|
| SCIM base URL | https://api.kortix.com/scim/v2/accounts/<account_id>. It has no /v1. A self-hosted instance uses its own API origin. |
| Auth | Authorization: Bearer kortix_scim_… |
| User identifier | userName = the person’s email |
The guided setup shows each step in the IdP console. Check these settings:
- Okta: set Unique identifier field for users to
userNameand Authentication Mode to HTTP Header. Okta pushes changes as they happen. - Microsoft Entra ID: automatic provisioning needs Entra ID P1 or P2. Keep
userName→user.userprincipalname. Entra syncs about every 40 minutes. Provision on demand pushes one person at once.
Kortix checks the scim entitlement on every SCIM request, so a token stops
working when the account loses it.
What the endpoints do
| Endpoint | Supports |
|---|---|
/ServiceProviderConfig, /ResourceTypes, /Schemas |
Discovery |
/Users |
GET (list, one), POST, PUT, PATCH, DELETE |
/Groups |
GET (list, one), POST, PUT, PATCH (add and remove members), DELETE |
- Filters: one
attribute eq "value"clause./UsersmatchesuserName,id, andexternalId./GroupsmatchesdisplayName,id, andexternalId. A filter in any other form returns400. A filter on another attribute returns an empty list. - New person: a
POST /Usersfor an email with no Kortix sign-in creates a pending invitation with thememberrole, valid for 14 days. SCIM lists it as an active user. A person who already has a Kortix sign-in joins as amember. - Groups: a SCIM group is an ordinary Kortix group. Give it project roles like any other.
- Remove a person:
active: falseorDELETEremoves the membership, its roles and groups, and revokes the person’s keys and live session tokens. - Last owner: deactivating the account’s last owner returns
409.
API keys and tokens
Every Kortix credential starts with a prefix that names its kind.
| Prefix | Credential | Acts as | Get one |
|---|---|---|---|
kortix_pat_ |
Personal access key | You, with your roles. Optionally one project only. | Settings → Personal access keys, kortix tokens new, kortix login |
kortix_pat_ |
Project CLI token | You, on one project only | kortix projects cli-tokens new |
kortix_sa_ |
Service account key | The service account. It has no access until a role is assigned. | Account settings → API keys, kortix tokens service-accounts new |
kortix_oat_, kortix_ort_ |
OAuth access token (1 hour), refresh token (30 days) | The person who approved the app | Sign in with Kortix |
kortix_gw_ |
Gateway key | Model calls through one project’s LLM gateway | kortix gateway keys new (Models) |
kortix_scim_ |
SCIM token | Directory sync for one account | Account settings → Identity |
kortix_pat_ |
Session token, in KORTIX_TOKEN |
The agent of one session | Kortix sets it in the sandbox. It ends with the session. |
Kortix shows a secret once, when you create it, and stores only its hash.
Connected apps (kortix_oat_) cannot create keys, service accounts, SCIM
tokens, or OAuth apps (403).
Personal access keys
A personal access key acts as the member who created it. It holds exactly that
member’s roles and stops working when the membership ends. Every member can
create and revoke their own keys. Revoking someone else’s key needs
token.revoke.
kortix tokens new ci-deploy --expires 90d # print the secret once
kortix tokens new laptop --project <project_id> # this project only
kortix tokens ls --mine
kortix tokens rm <token_id>
--expires takes an ISO-8601 instant or a span: 30d, 12h, 6w, 1y. A key
bound to one project gets 403 on every other project and on account actions.
For a key bound to the current project, use
kortix projects cli-tokens new [--expires-at <iso>].
Service accounts
A service account is its own principal, for CI and automations that must not act as a person. It starts with no access.
kortix tokens service-accounts new nightly-reporter --description "Cron"
kortix access grant --service-account <id> --role member --project <project_id>
kortix tokens service-accounts disable <id> # stops it authorizing
kortix tokens service-accounts rm <id> # deletes it
A disabled service account cannot be enabled again. Create a new one. Each agent also has a service account. Bind its ceiling role in Account settings → Projects → the project → Grant access → Agents, not here. See What an agent may do.
Key rules
Account settings → API keys → Key rules governs the personal access keys and project CLI tokens people create in the account. Keys Kortix creates for a running session follow the session instead.
| Rule | Field | Limit | Effect |
|---|---|---|---|
| Require an end date | require_expiry |
On or off | A key without an expiry is refused: 400 code: "expiry_required". |
| Longest a key can last | max_lifetime_days |
1 to 730 days | A later expiry is refused: 400 code: "expiry_too_far". |
| Turn off unused keys | idle_revoke_days |
1 to 365 days | A key unused for this long is revoked on its next use. Keys bound to one project are exempt. |
The first two rules apply when a key is created. Turn off unused keys also applies to existing keys.
OAuth apps and connected apps
Register an OAuth app
An OAuth app signs Kortix members in on your own site (“Sign in with Kortix”).
- Open Account settings → API keys → OAuth apps and select Register app.
- Enter a name, the type, the redirect URIs, and the scopes.
- Copy the client id and, for a confidential app, the client secret. The secret is shown once.
| Field | Values |
|---|---|
| Type | Confidential: a server-side app with a client secret. Public: a browser or native app with PKCE and no secret. Fixed at registration. |
| Redirect URIs | Matched byte for byte. https, except localhost. |
| Scopes | profile (who the person is), email, kortix (act as the person on the Kortix API). Default: all three. |
| Active | Off stops new sign-ins without deleting the app. |
Rotate secret issues a new secret, and the old one stops working at once.
Delete app ends every token the app holds. In code, use
kortix.iam.oauthClients (list, get, create, update, rotateSecret,
remove). The sign-in flow is in
Sign in with Kortix.
Connected apps
A connected app is an app you approved with Sign in with Kortix, for example an MCP client such as Claude Code or Cursor. It acts as you, in every account you belong to, until you revoke it. See Kortix MCP server.
- Web: Settings → Personal access keys → Connected apps → Revoke access.
- CLI:
kortix tokens apps lsandkortix tokens apps rm <client-id>.
Revoking deletes your approval, and the app’s tokens stop working on their next request. The app must ask you again.
Enterprise features
An entitlement decides whether a feature exists for the account. The role still decides who may use it. The Enterprise plan holds all five.
| Entitlement | Unlocks |
|---|---|
sso |
SAML SSO, domain verification, Enforce SSO |
scim |
SCIM provisioning and SCIM tokens |
rbac |
Custom roles; creating, editing, and adding members to groups |
auditAccess |
Reading and exporting the audit log, audit webhooks |
branding |
Branding |
Without the entitlement, the gated route returns 402 with
code: "entitlement_required" and entitlement set to its key. A SCIM request
(/scim/v2/...) from an account without scim gets 403. Removing a
configuration (an SSO provider, a SCIM token) never needs the entitlement. Plans
are on Plans & credits.
On a self-hosted instance, a Kortix Enterprise license unlocks all five for
every account: set ENTERPRISE_LICENSE_AVAILABLE=true, or install with
kortix self-host init --enterprise-license. See
Self-hosting.