Skip to content
Lumaft documentation contents
Lumaft documentation

Federated identity

Connect OIDC, SAML, trusted-proxy sign-in, and SCIM provisioning, with walkthroughs for Okta and Microsoft Entra ID.

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 exact issuer, the protocol, and a provisioning mode.
  • The identity Lumaft trusts is the registered issuer plus the provider's immutable subject — the OIDC sub claim, the SAML persistent NameID, 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.
  • administered mode pre-links each subject to an existing account; an unknown subject fails without creating anything. on-first-login creates 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_ORIGIN set to the exact HTTPS origin browsers use, for example https://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.

ScreenshotUsers & Access → Identity showing one registered provider with its issuer key, issuer, protocol, provisioning mode, and the enabled state

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-idpCORP_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.

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.

ScreenshotThe Lumaft sign-in screen showing the local username and password form and, below it, a "Sign in with corp-idp" provider action

Walkthroughs

Provider consoles change; the values are what matter.

Okta — OIDC

  1. Applications → Create App Integration → OIDC - OpenID Connect → Web Application.
  2. Sign-in redirect URI: <origin>/api/v1/auth/oidc/corp-idp/callback. Leave sign-out redirects empty.
  3. Note the Client ID and Client secret.
  4. 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.
  5. Assign the users or groups who may sign in. Assignment gates access at Okta; it does not create Lumaft accounts.
  6. The immutable subject is Okta's user ID (the sub claim). Find it on the user's profile URL or through the Okta API when linking accounts.

Microsoft Entra ID — OIDC

  1. App registrations → New registration. Platform Web, redirect URI <origin>/api/v1/auth/oidc/corp-idp/callback.
  2. Certificates & secrets → New client secret. Note the value now; it is shown once.
  3. Note the Application (client) ID and the Directory (tenant) ID.
  4. Issuer: https://login.microsoftonline.com/<tenant-id>/v2.0. Register that exact string.
  5. Under Enterprise applications, set Assignment required and assign users, so only assigned people can start a sign-in.
  6. The sub claim 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 in on-first-login mode, have each person sign in once (Lumaft creates a viewer bound to their subject), promote as needed, then switch the mode to administered so no further accounts are created.

Okta — SAML

  1. Applications → Create App Integration → SAML 2.0.
  2. Single sign-on URL: <origin>/api/v1/auth/saml/corp-idp/acs. Audience URI (SP entity ID): <origin>/api/v1/auth/saml/corp-idp.
  3. Name ID format: Persistent. Application username: a value that never changes for a user — use the Okta user ID (user.id in a custom expression), not email or username.
  4. Leave assertion encryption off; Lumaft refuses encrypted assertions. Sign the response.
  5. 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 the issuer), and download the X.509 certificate (into LUMAFT_SAML_CORP_IDP_IDP_CERT).

Microsoft Entra ID — SAML

  1. Enterprise applications → New application → Create your own application → Integrate any other application (non-gallery), then Single sign-on → SAML.
  2. Identifier (Entity ID): <origin>/api/v1/auth/saml/corp-idp. Reply URL (ACS): <origin>/api/v1/auth/saml/corp-idp/acs.
  3. Unique User Identifier (Name ID): format Persistent, source attribute user.objectid — never user.userprincipalname or user.mail.
  4. Do not enable token encryption. Keep the default signed response.
  5. Copy the Login URL (into LUMAFT_SAML_CORP_IDP_SSO_URL), the Microsoft Entra Identifier (register it as the issuer), and download Certificate (Base64) (into LUMAFT_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.

  1. Issue the token from Users & Access or POST /api/v1/identity/scim-tokens with { "issuerKey": "corp-idp", "name": "okta-scim" }. Copy the secret once; GET /api/v1/identity/scim-tokens never returns it again.
  2. Give the provider the base URL <origin>/api/v1/scim/v2/corp-idp and the token as the bearer secret.
  3. Map externalId to the same immutable subject the sign-in path uses. If externalId is omitted, Lumaft treats userName as 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-login provider 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.