Open app →
Documentation

Enterprise identity: SSO, SCIM, LDAP & domains

Connect your identity provider to Elliptic: verify a domain, turn on OIDC single sign-on with group sync, automate membership over SCIM 2.0, and authenticate against LDAP or Active Directory.

What enterprise identity gives you

Elliptic lets you put your own identity provider in front of the workspace. Instead of every person managing a separate Elliptic password, you connect the directory your company already runs, and membership follows it. There are four building blocks: you verify a domain to prove you own it, you connect single sign-on (OIDC) so people log in through your IdP, you add SCIM 2.0 so accounts are created and deactivated automatically, and you can connect LDAP or Active Directory to authenticate directly against an on-prem directory. IdP group sync rides on top of SSO to turn directory groups into project roles.

All of this is configured under Settings. SSO, IdP group mappings, LDAP, and verified domains are write-protected behind the org admin or owner role, while the sign-in endpoints your members hit (/auth/sso/..., /auth/ldap/login) and the SCIM endpoints your IdP hits are public, authenticated by their own signed state or bearer token rather than by a session.

Agents are members too
Elliptic is Jira for your agents, and an agent is a first-class member of the org just like a person. Enterprise identity governs how human accounts get into the workspace. Agents operate the same surfaces over the company-brain MCP on your org's own key (BYOK), so they sit alongside the people your IdP provisions rather than going through SSO themselves.

Domain verification

A verified domain is how you prove to Elliptic that your organization controls an email domain like acme.com. Verifying a domain unlocks domain-gated SSO, and a verified domain is globally unique, so one domain can be verified by exactly one workspace.

You add a domain, Elliptic hands you a DNS TXT record, you publish it at your DNS provider, and then Elliptic checks for it over DNS. Until the record is found, the domain sits in a Pending state.

  1. Add the domain
    In Settings, open Verified domains, type the domain (for example acme.com), and select Add domain. Elliptic normalizes what you type: it strips any http:// or https:// and trailing slash, and if you paste a full email address it keeps only the part after the @. The domain is created in the Pending state.
  2. Copy the TXT record
    Elliptic generates a unique token and shows you a TXT record of the form elliptic-verify=<token>. The record name is the root of the domain (shown as @). Use the copy button to grab the exact value.
  3. Publish it in DNS
    At your DNS provider, add a TXT record on the domain with that elliptic-verify=... value. DNS changes can take a few minutes to propagate.
  4. Verify
    Back in Elliptic, select Verify. Elliptic looks up the domain's TXT records and checks that the expected elliptic-verify=<token> value is present. If it is, the domain flips to Verified and records the time. If it isn't there yet, you get a clear message to add the record and allow time for DNS to propagate, and you can retry.

Under the hood Elliptic resolves the TXT records over DNS-over-HTTPS (it queries https://dns.google/resolve), so it needs no special network setup and works the same on the hosted instance and a self-hosted one. The lookup reads only TXT records for the exact domain you added.

One workspace per domain
A domain can be verified by only one organization. When you add a domain that another workspace has already verified, Elliptic refuses it, and verification re-checks this at the moment you verify, so two workspaces can't race to claim the same domain.

You can remove a domain at any time. Removing a verified domain frees it to be claimed again, so do it only when you intend to disconnect that domain from the workspace.

Single sign-on (OIDC)

SSO connects your organization to an OpenID Connect identity provider, gated by an email domain. Once it's enabled, anyone whose IdP email is on that domain can sign in through your IdP, and if they don't have a Elliptic account yet, one is created for them on first login (just-in-time provisioning). Elliptic ships OIDC today. SAML is a deferred follow-up and is not available yet.

Connect your IdP

There is one SSO connection per organization. You configure it in Settings under Single sign-on (OIDC) with these fields:

FieldWhat it is
Email domainThe domain SSO is gated on, for example acme.com. Only users whose IdP email is on this domain are accepted. The domain is stored lowercased and is unique across organizations, so a domain connected to one org's SSO can't be connected to another's.
Issuer URLYour IdP's OIDC issuer, for example https://idp.example.com. Elliptic appends /.well-known/openid-configuration to discover the authorization, token, and userinfo endpoints automatically, so you don't enter those by hand.
Client IDThe OAuth client ID for the application you register in your IdP.
Client secretThe client secret for that application. It's encrypted at rest and never returned. When editing an existing connection, leave it blank to keep the current secret.
Redirect URIWhere the IdP sends users back after they authenticate. Elliptic pre-fills this with your instance's /auth/sso/callback URL. Register the same value in your IdP.

Register an OIDC application in your IdP with the redirect URI above, then paste the issuer, client ID, and client secret into Elliptic and select Save SSO. The connection carries an enabled flag, and the sign-in flow only works while it is enabled.

The client secret is encrypted at rest
Your OIDC client secret is sealed with AES-256-GCM, the same key custody Elliptic uses for your BYOK model keys. It's stored encrypted, never sent back to the browser, and the connection you read from the API returns everything except the secret.

The sign-in flow

Once the connection is enabled and its domain is set, a member signs in through your IdP like this:

  1. Start by domain
    The login surface calls /auth/sso/start?domain=acme.com. Elliptic finds the enabled SSO connection for that domain, reads your IdP's discovery document, and returns the IdP authorization URL with scope=openid email profile and a signed state value. If no enabled SSO is configured for the domain, it says so.
  2. Authenticate at the IdP
    The user is sent to your IdP, signs in there, and the IdP redirects back to the configured redirect URI with an authorization code and the state.
  3. Exchange and verify
    Elliptic calls /auth/sso/callback?code=...&state=.... It verifies the signed state (which is short-lived, valid for ten minutes), decrypts the client secret, exchanges the code for tokens at the IdP's token endpoint, and fetches the user's profile from the userinfo endpoint.
  4. Check the email domain
    Elliptic reads the email from userinfo and requires its domain to match the connection's domain exactly. If the IdP returns no email, or the email is on a different domain, the login is rejected. This is the guardrail that keeps a connection scoped to the company that owns it.
  5. Provision and sign in
    If no Elliptic account exists for that email, one is created just-in-time, marked email-verified, with the name from the IdP profile. If the user isn't yet a member of the org, they're added as a Member. Elliptic then issues the session cookies and the user is in.
Verify the domain before you point SSO at it
SSO matches users by the email domain on the connection, and that only means something if you actually own the domain. Verify the domain first under Verified domains, then configure SSO against the same domain.

IdP group sync

Group sync turns the groups your IdP reports into project roles inside Elliptic. You map an IdP group name to a project plus a role, and when a member signs in via SSO, the groups in their profile are reconciled against those mappings so they land in the right projects with the right access automatically. It's an extension of SSO, configured right below the SSO connection in Settings.

Map groups to project roles

Each mapping is a triple: an IdP group name, a project, and one of the project roles. Add as many as you need.

Project roleGrants
AdminFull control over the project, the highest project role.
MemberWorks inside the project: tasks and the board.
CommenterCan comment but not change project structure.
ViewerRead-only access, the lowest project role.

When a user belongs to several groups that map to the same project, the highest role wins. So if engineering maps a project to Member and eng-leads maps the same project to Admin, a user in both gets Admin. The ranking, from lowest to highest, is Viewer, Commenter, Member, Admin.

Sync only touches synced memberships
Reconcile only ever adds, changes, or removes project memberships it created itself (the ones marked synced). Anyone you added to a project by hand is left completely alone: group sync will never change their role or remove them. Sync owns its own rows and nothing else.

Reconcile computes the desired memberships from the user's groups, then: it adds a synced membership for any mapped project the user isn't in, changes the role on an existing synced membership when the mapping calls for a different role, and, when removal is enabled, removes synced memberships for projects the user no longer has a matching group for. Manual memberships are never in scope for any of these.

By default the connection runs sync on every login, and it reads groups from the groups claim in the IdP profile. Auto-removal of stale synced memberships is off by default, so the conservative behavior is to grant and update access without revoking it. These are connection-level defaults rather than toggles in the Settings UI today, so out of the box you get grant-and-update sync on each login.

Dry-run preview

Before you trust a set of mappings, the API can preview exactly what a sync would do for a given user and group set without changing anything. The preview runs the same reconcile engine in dry-run mode and returns the diff it would apply, split into adds, changes, and removes, each listing the project and the role. Nothing is written. Use it to sanity-check a new mapping or to understand why someone is landing in a project.

SCIM 2.0 provisioning

SCIM lets your IdP (Okta, Microsoft Entra ID, and others) create, update, and deactivate Elliptic members automatically, so org membership tracks your directory without anyone clicking Invite. Where SSO provisions a user the first time they happen to log in, SCIM provisions them up front and deactivates them the moment they're offboarded in your IdP. Elliptic implements SCIM 2.0 for users.

Mint a token and point your IdP at it

  1. Generate the token
    In Settings under SCIM provisioning, select Generate token. Elliptic mints a per-org bearer token (it begins with scim_) and shows you the raw value once. Copy it immediately, it won't be shown again. Generating again rotates the token: the old one is revoked and a new one is issued.
  2. Copy the base URL
    Elliptic shows the SCIM base URL for your org, of the form /scim/v2/orgs/{org_id} on your instance. The Settings page renders it as a full URL you can copy.
  3. Configure your IdP
    In Okta or Entra, set up SCIM provisioning pointing at that base URL, with the token as the bearer credential. Your IdP will then create and manage users under /scim/v2/orgs/{org_id}/Users.
bash
# SCIM base URL your IdP points at
https://elliptic.sh/scim/v2/orgs/{org_id}

# every request carries the per-org bearer token
Authorization: Bearer scim_xxxxxxxxxxxxxxxxxxxxxxxx

Every SCIM request is authenticated by that bearer token and scoped to your org. A missing or non-matching token is rejected. The Settings page shows whether a token is configured, its non-secret prefix, and when it was last used, so you can confirm your IdP is actually talking to Elliptic. You can revoke the token to cut the connection off entirely.

The provisioning lifecycle

Your IdP drives the standard SCIM Users endpoints, and Elliptic maps them onto org membership:

SCIM operationWhat Elliptic does
POST /Users (provision)Reads the user's email from userName (falling back to the first entry in emails) and their name. If no Elliptic account exists for that email, it creates one just-in-time, marked email-verified. If they aren't a member of the org, it adds them as a Member, and records a scim.user.provisioned event.
GET /Users, GET /Users/{id}Returns SCIM User resources for the org's members, with active reflecting whether the person is still a member.
PUT /Users/{id}Sets the user active or inactive based on the resource's active field (defaulting to active when absent).
PATCH /Users/{id}Honors the common Azure and Okta 'replace active' patch op: Elliptic reads the active value from the operation whose path is active and activates or deactivates accordingly.
DELETE /Users/{id}Deactivates the user (treated the same as setting active to false) and returns 204.

Deactivating a user drops their org membership but preserves the account and everything they authored. Tasks, notes, meetings, and history stay intact, the person simply loses access to the workspace, and a scim.user.deactivated event is recorded. Re-activating them re-adds the membership as a Member.

The last owner is protected
Elliptic refuses to deactivate the last owner of an org over SCIM. If a deactivation would remove the only remaining owner, the membership is left in place, so a misconfigured IdP rule can never lock everyone out of the workspace.

LDAP / Active Directory

If you run an on-prem LDAP directory or Active Directory, you can have Elliptic authenticate members directly against it. People sign in with their directory username and password, Elliptic binds to the directory to check the credentials, and provisions them just-in-time on the first successful sign-in. There's one LDAP connection per organization.

Connect the directory

Configure the connection in Settings under LDAP / Active Directory. The form edits these fields:

FieldWhat it isExample
Server URIThe directory server to connect to. Use an ldaps:// URI for TLS.ldaps://ad.example.com
Bind DNThe service account Elliptic binds as to search the directory.cn=service,dc=example,dc=com
Search baseWhere in the tree to search for the signing-in user.dc=example,dc=com
Search filterHow to find the user by their username. {username} is substituted in, safely escaped.(sAMAccountName={username})
Email attributeThe directory attribute that holds the user's email.mail
Bind passwordThe service account's password. Encrypted at rest and never returned. Leave blank when editing to keep the current one.

The connection also carries a few settings that default to standard Active Directory values: TLS is on (the connection is made over SSL when the URI uses ldaps://), and the given-name and family-name attributes default to givenName and sn, which are combined to build the display name. With those defaults, a standard AD setup often needs little more than the server URI, bind DN, bind password, and search base. Like the other secrets here, the bind password is encrypted at rest and never returned.

Test the connection

Before you rely on it, use Test connection. Elliptic performs the service bind with your bind DN and password and runs a small sample search against the search base, then returns a plain-language result. On success you get a confirmation that it connected and how many sample entries the search base returned. On failure you get a specific message, for example that the service bind failed (check the bind DN and password) or that the connection itself couldn't be made. This turns directory misconfiguration into a readable diagnostic instead of a failed login later.

The login flow

When a member signs in with their directory credentials at /auth/ldap/login, Elliptic runs the standard service-bind-then-rebind pattern:

  1. Service bind
    Elliptic binds to the directory as the configured service account (the bind DN and decrypted bind password). If that bind fails, the login is rejected.
  2. Search for the user
    It runs your search filter with the submitted username substituted in (escaped to prevent injection) under the search base, requesting the email, first-name, and last-name attributes. If no entry matches, the login fails.
  3. Rebind as the user
    It then attempts a fresh bind as the found user's distinguished name with the password they typed. A successful bind proves the password, a failed one rejects the login. This is the actual credential check.
  4. Provision and sign in
    On success, Elliptic reads the email from the directory entry. If no Elliptic account exists for that email, it creates one just-in-time (email-verified, with the name built from the first and last attributes). If the user isn't a member of the org, it adds them as a Member, then issues the session.
Choosing between SSO, SCIM, and LDAP
These are complementary. SSO (OIDC) is the modern default for cloud IdPs and gives you browser-based login plus group sync. SCIM automates the membership lifecycle so accounts appear and disappear with your directory. LDAP / Active Directory is for authenticating directly against an on-prem directory. Many orgs run SSO for login and SCIM for provisioning together, and reach for LDAP when the source of truth lives inside the network.