Federated identity
Enterprise installations can let an identity provider vouch for who a person is. Lumaft still decides what that person may do: every federated identity maps to a Lumaft account, role, and permission set, and no claim from the provider ever grants a permission directly.
Federation is additive. Local sign-in keeps working, a provider outage never removes it, and you keep a local administrator with a tested recovery procedure throughout.
How it works
browser ──▶ /api/v1/auth/<provider>/<issuerKey>/start ──▶ IdP ──▶ callback ──▶ Lumaft
│
registered issuer + immutable subject ──▶ account
- A provider registration names an
issuerKey(yours, permanent), the exactissuer, the protocol, and a provisioning mode. - The identity Lumaft trusts is the registered issuer plus the provider's immutable subject
— the OIDC
subclaim, the SAML persistentNameID, or the header a trusted proxy injects. Email, display name, groups, and roles are never used to select, link, or authorize an account, because all of them can change or be reassigned. administeredmode pre-links each subject to an existing account; an unknown subject fails without creating anything.on-first-logincreates a viewer on a verified first sign-in. Neither mode ever creates an administrator.
Before you begin
- An Enterprise entitlement on the installation (Administration → Licensing).
LUMAFT_PUBLIC_ORIGINset to the exact HTTPS origin browsers use, for examplehttps://lumaft.example.com, on every replica.- An account with
accounts:manage, and a second local administrator you can still sign in with if the provider misbehaves. - Pick your issuer key now: 1–64 lowercase letters, digits, or dashes, starting with a letter or
digit. It appears in URLs and environment variable names and cannot be changed later. This
page uses
corp-idp.
Step 1: Register the provider
From Administration → Users & Access → Identity, or:
POST /api/v1/identity/providers
{ "issuerKey": "corp-idp", "issuer": "<exact issuer>", "provider": "oidc", "provisioningMode": "administered" }
| Field | Value |
|---|---|
issuerKey |
corp-idp |
issuer |
OIDC: the issuer URL discovery advertises. SAML: the IdP entity ID. Trusted proxy: a realm name you choose |
provider |
oidc, saml, or trusted-proxy |
provisioningMode |
administered (recommended) or on-first-login |
The binding of key to issuer is permanent. To point corp-idp at a different issuer, register a
new key.
Step 2: Configure the identity provider
Give the provider these Lumaft values. <origin> is LUMAFT_PUBLIC_ORIGIN.
OIDC
| Provider setting | Value |
|---|---|
| Application type | Web application, authorization-code flow |
| Redirect / callback URI | <origin>/api/v1/auth/oidc/corp-idp/callback — exact match, no wildcard |
| Scopes | openid (Lumaft requests what it needs) |
| PKCE | Enabled (Lumaft always uses it) |
Lumaft discovers endpoints from the registered issuer and validates issuer, audience, signature, nonce, and PKCE on every round trip. Round trips are single-use and expire after ten minutes.
SAML
| Provider setting | Value |
|---|---|
| SP entity ID / audience | <origin>/api/v1/auth/saml/corp-idp |
| Assertion consumer service (ACS) | <origin>/api/v1/auth/saml/corp-idp/acs |
| Binding | HTTP-Redirect for SSO; HTTP-POST to the ACS |
| NameID format | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent |
| NameID value | The user's immutable identifier, not username or email |
| Response signing | Signed responses. Encrypted assertions are refused |
SAML is SP-initiated only; IdP-initiated (unsolicited) responses are refused. Transient and email-address NameID formats are refused.
Trusted proxy
Your proxy authenticates the user, then forwards a request carrying an immutable subject in a
header and proves itself with a shared secret in x-lumaft-trusted-proxy-secret.
- Strip any client-supplied copy of the subject and secret headers at the proxy before injecting the verified values.
- Restrict direct network access to Lumaft so nothing but the proxy can reach it.
- Protect the proxy-to-Lumaft hop (private network or TLS).
Lumaft checks the secret and reads the subject; it does not install or configure the proxy.
Step 3: Set the protocol variables
<KEY> is the issuer key uppercased with dashes changed to underscores: corp-idp →
CORP_IDP. Set them on every replica through your platform's secret mechanism and restart.
| Provider | Variables |
|---|---|
| OIDC | LUMAFT_OIDC_CORP_IDP_CLIENT_ID, LUMAFT_OIDC_CORP_IDP_CLIENT_SECRET |
| SAML | LUMAFT_SAML_CORP_IDP_SSO_URL, LUMAFT_SAML_CORP_IDP_IDP_CERT (PEM), optional LUMAFT_SAML_CORP_IDP_NAMEID_FORMAT |
| Trusted proxy | LUMAFT_TRUSTED_PROXY_CORP_IDP_SUBJECT_HEADER, LUMAFT_TRUSTED_PROXY_CORP_IDP_SHARED_SECRET (≥ 32 characters), optional LUMAFT_TRUSTED_PROXY_CORP_IDP_DISPLAY_HEADER |
Missing or invalid variables refuse sign-in through that provider with a closed reason; they never affect local sign-in.
Step 4: Link people to accounts
In administered mode, link each subject before that person signs in:
POST /api/v1/identity/links
{ "issuerKey": "corp-idp", "subject": "<immutable subject>", "userId": "<Lumaft user id>" }
The subject is the value the provider will send — an Okta user ID, an Entra object ID, a persistent NameID — not an email. Get it from the provider's user record.
In on-first-login mode nothing is linked in advance; a verified first sign-in creates a viewer
account. Promote it afterwards from Users & Access if the person needs more. Switch modes
with PUT /api/v1/identity/providers/corp-idp/mode.
Step 5: Test
Open <origin>/api/v1/auth/oidc/corp-idp/start (or saml, trusted-proxy) or use the
provider's action on the sign-in screen. Sign in at the provider. You land in Lumaft as the
linked account.
Walkthroughs
Provider consoles change; the values are what matter.
Okta — OIDC
- Applications → Create App Integration → OIDC - OpenID Connect → Web Application.
- Sign-in redirect URI:
<origin>/api/v1/auth/oidc/corp-idp/callback. Leave sign-out redirects empty. - Note the Client ID and Client secret.
- Issuer: your org authorization server,
https://<org>.okta.com(or the custom authorization server's issuer,https://<org>.okta.com/oauth2/default, if you use one). Register that exact string. - Assign the users or groups who may sign in. Assignment gates access at Okta; it does not create Lumaft accounts.
- The immutable subject is Okta's user ID (the
subclaim). Find it on the user's profile URL or through the Okta API when linking accounts.
Microsoft Entra ID — OIDC
- App registrations → New registration. Platform Web, redirect URI
<origin>/api/v1/auth/oidc/corp-idp/callback. - Certificates & secrets → New client secret. Note the value now; it is shown once.
- Note the Application (client) ID and the Directory (tenant) ID.
- Issuer:
https://login.microsoftonline.com/<tenant-id>/v2.0. Register that exact string. - Under Enterprise applications, set Assignment required and assign users, so only assigned people can start a sign-in.
- The
subclaim Entra issues is stable per user per application, which is what Lumaft needs, but it is pairwise — not the user's object ID — and the portal does not display it. The practical path: register the provider inon-first-loginmode, have each person sign in once (Lumaft creates a viewer bound to their subject), promote as needed, then switch the mode toadministeredso no further accounts are created.
Okta — SAML
- Applications → Create App Integration → SAML 2.0.
- Single sign-on URL:
<origin>/api/v1/auth/saml/corp-idp/acs. Audience URI (SP entity ID):<origin>/api/v1/auth/saml/corp-idp. - Name ID format: Persistent. Application username: a value that never changes for a user
— use the Okta user ID (
user.idin a custom expression), not email or username. - Leave assertion encryption off; Lumaft refuses encrypted assertions. Sign the response.
- From the app's sign-on settings, copy the Identity Provider Single Sign-On URL (into
LUMAFT_SAML_CORP_IDP_SSO_URL), the Identity Provider Issuer (register it as theissuer), and download the X.509 certificate (intoLUMAFT_SAML_CORP_IDP_IDP_CERT).
Microsoft Entra ID — SAML
- Enterprise applications → New application → Create your own application → Integrate any other application (non-gallery), then Single sign-on → SAML.
- Identifier (Entity ID):
<origin>/api/v1/auth/saml/corp-idp. Reply URL (ACS):<origin>/api/v1/auth/saml/corp-idp/acs. - Unique User Identifier (Name ID): format Persistent, source attribute
user.objectid— neveruser.userprincipalnameoruser.mail. - Do not enable token encryption. Keep the default signed response.
- Copy the Login URL (into
LUMAFT_SAML_CORP_IDP_SSO_URL), the Microsoft Entra Identifier (register it as theissuer), and download Certificate (Base64) (intoLUMAFT_SAML_CORP_IDP_IDP_CERT).
SCIM provisioning
SCIM lets the provider create and deactivate Lumaft accounts for the same immutable subjects. It uses its own registration-bound bearer credential, separate from browser sessions and integration tokens.
- Issue the token from Users & Access or
POST /api/v1/identity/scim-tokenswith{ "issuerKey": "corp-idp", "name": "okta-scim" }. Copy the secret once;GET /api/v1/identity/scim-tokensnever returns it again. - Give the provider the base URL
<origin>/api/v1/scim/v2/corp-idpand the token as the bearer secret. - Map
externalIdto the same immutable subject the sign-in path uses. IfexternalIdis omitted, Lumaft treatsuserNameas that subject — not as an email lookup.
| Provider | Where |
|---|---|
| Okta | The app's Provisioning tab → Configure API integration: SCIM connector base URL, HTTP Header authentication with the token. Enable Create Users and Deactivate Users |
| Entra ID | The enterprise app's Provisioning page: Tenant URL and Secret Token, then Test Connection and assign users |
What SCIM does and does not do:
- Supported: user create, read, replace, patch, delete;
ServiceProviderConfig,ResourceTypes,Schemas; filtering by subject equality. - Creation assigns exactly the viewer role. Group and role attributes never grant Lumaft permissions; promote people in Lumaft.
- Deactivation revokes the identity's sessions. Delete means deactivate; historical rows remain.
- Not supported: groups, bulk operations, sorting, ETags, password management.
- A token sees only its own provider. Provisioning writes require the Enterprise entitlement; a lapse refuses writes without deleting identities.
Offboarding
- One person: disable the account, or unlink the identity, from Users & Access. Either revokes that identity's sessions in the same transaction. Deactivating through SCIM does the same.
- A whole provider: disabling the registration stops new sign-ins but does not revoke existing sessions — disable the accounts or wait out the twelve-hour session lifetime.
- Reconciliation for an
on-first-loginprovider accepts the provider's current subject set and disables absent identities. Empty sets are refused, and so is any action that would remove the last enabled administrator's last identity. A provider outage never counts as an empty directory. - Do not use license lapse as an offboarding control. A lapse retains registrations and identities and keeps configured sign-in paths working; only identity administration and SCIM writes stop.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Provider returns a redirect-URI error | The callback URI at the provider is not exactly <origin>/api/v1/auth/oidc/corp-idp/callback |
Fix it at the provider; check LUMAFT_PUBLIC_ORIGIN has no trailing slash |
| Sign-in refused after a successful IdP login | Issuer mismatch: the registered issuer differs from what discovery or the assertion reports |
Register the exact issuer string the provider publishes |
Refused with an unknown-subject reason (administered) |
No link exists for this subject | Link the subject, or use on-first-login for the first sign-in |
| SAML response refused | Encrypted assertion, unsolicited (IdP-initiated) response, or a non-persistent NameID | Turn off encryption, start from Lumaft, set the NameID format to persistent |
| Round trip refused after a pause | Round trips expire after ten minutes and are single-use | Start again |
| Works on one replica, fails on another | Protocol variables missing on that replica | Apply identical settings to every replica and restart |
| Local sign-in also broken | Not federation: check TLS and LUMAFT_ALLOW_HTTP in Troubleshooting |
Federation has protocol fixtures, not a certification matrix for every provider. Validate your provider's immutable subject, protocol settings, and offboarding behavior on a test account before rolling out.