Skip to main content

Authentication

Authentication establishes who is making a request; permissions then decide what they may do. Korint gives each tenant its own separate user directory, and every account belongs to exactly one tenant.

This page is the model: the kinds of identity the platform recognises and the order the checks run in. For the mechanics — credentials, the token request, hosts, scopes and CORS — see Authentication in the API reference.


Signing in

Users sign in with an email and password, or through single sign-on. Social sign-on is available with Google and Apple, and enterprise identity providers can be connected over SAML 2.0 or OpenID Connect (OIDC). The sign-in methods offered depend on the tenant's configuration. Because each tenant has its own directory, accounts are isolated per tenant and a user's session is only valid within their own tenant.

Anonymous sessions

Some tenants offer public, self-service quoting funnels that a visitor can start without an account. Where a tenant enables this, Korint issues a temporary anonymous session that can quote and capture details; when the visitor later signs in or creates an account, their work is handed off to the new account. Anonymous access is opt-in per tenant—it exists only where the tenant defines an anonymous role.

An anonymous session is itself an access token: POST /anonymous-session returns a sessionId and an accessToken you use as the bearer for that visitor's quoting calls, and POST /anonymous-session/handoff transfers the work once they sign in. The calls are covered in Anonymous quoting.


The three kinds of token

There is more than one kind of token, and they are not interchangeable. Choosing the wrong one produces errors that look like permission bugs. Obtaining them is covered in Authentication; what each one is follows here.

Client-credentials tokenan integration

Issued by the OAuth 2.0 client-credentials grant. Carries a scope claim and identifies a client, not a person. Use it to read configuration and to start anonymous sessions.

User tokena person signed in

Issued when a human signs in. Identifies a user, so record-level permissions resolve against them.

Signing in returns both an id token and an access token, and the API accepts only the access token — send AccessToken, not IdToken. The id token is the intuitive choice, since it is the one carrying the email and profile, and it is rejected with 401 INVALID_CREDENTIALS, which reads as though the credentials were wrong rather than the token being the wrong kind.

A user access token carries none of the korint.io/* scopes listed in Scopes — its authority comes from the user's permissions, not from that table.

Anonymous session tokena visitor in a public funnel

Returned by POST /anonymous-session as accessToken. Not a Cognito token and it carries no scope claim at all — its claims are { tenantId, sub: <sessionId>, type: "SESSION", iat, exp }, and it lasts 24 hours. Carrying no scope, it is refused outright by any endpoint that declares one. What such a session may do is listed in Anonymous quoting.

Record-level permissions resolve against a user. A client-credentials token that has not been provisioned with administrative access can therefore be rejected on policy operations with

404 USER_NOT_FOUND — "No user found for user id <client_id>"

even though the token, tenant header and scopes are all valid. Where you see this, the integration pattern is to mint an anonymous session for the visitor and act under that, or to act as a signed-in user — not to widen scopes, which will not help.


How a request is checked

A valid token is necessary but not sufficient. Every request passes up to three checks, in this order:

  1. Authentication — the token is well-formed, unexpired, and issued by the authorization server of the tenant the tenant header names.
  2. Permission — the fine-grained, role-based check described in Permissions, evaluated against the specific record being acted on: the policy, customer or firm you named.
  3. Scope — only on endpoints that declare one, and only after the permission check has passed. This is the check the scope table feeds, and it is about client-credentials tokens: an integration must carry the scope covering that area. It is not what gates a signed-in user, whose access is settled by step 2. An anonymous session, carrying no scope at all, is refused by it — which is why a public funnel cannot reach the scoped endpoints listed in Anonymous quoting.

A 403 therefore means one of two things: your identity may not act on that record, or your token lacks a scope the endpoint requires.

Note what step 1 does not do: a request carrying no token at all is not rejected there. It is marked unauthenticated and allowed through, so the permission check is what refuses it — with 403 FORBIDDEN on most of the API rather than a 401. Only a malformed, expired or wrong-tenant token fails step 1, with 401 INVALID_CREDENTIALS.


Tenant isolation

Every request carries its tenant, and the caller's session is verified against that tenant's own user directory. Permissions and data access are then scoped to that tenant, so one tenant's users can never see or act on another tenant's data. A request that arrives without a tenant is rejected.