Skip to content

SAML single sign-on

Requires a license with the saml feature. See pricing.

SAML single sign-on lets your team sign in to the admin console through your company's identity provider. LyEve acts as the SAML service provider: it sends people to the provider, checks the signed answer that comes back, and starts a console session. Each tenant has its own providers.

StepWhat happens
StartThe browser opens /api/admin/auth/saml/{provider}. LyEve redirects it to the provider with a signed request.
Sign inThe person signs in at the provider.
AssertionThe provider posts its answer to /api/admin/auth/saml/{provider}/acs. LyEve checks it and finds or creates the account by email.
SessionLyEve sets the session cookie and redirects to /admin, or to the path given in ?redirect=.

What you can rely on:

  • Sign-in starts from LyEve. An answer the provider sends without a request from LyEve is refused.
  • Each assertion is accepted once. A replayed assertion is refused with 409.
  • An answer larger than 1 MiB, or one carrying a DOCTYPE or entity declaration, is refused.
  • The provider can never grant admin or super_admin. Those roles are dropped. A new user with no other role gets editor.
  • LyEve signs its requests with a certificate it generates for each provider, valid for one year. The private key is encrypted at rest and never returned.
  • A sign-in for an email that already has an account in the tenant signs in to that account, with the roles stored in LyEve. The provider decides who may claim which email, so connect only a provider you trust with every account in the tenant.
  1. Run with a license that carries saml. See licensing and tiers.
  2. Set LYEVE_BASE_URL to the public address of the instance. In production, sign-in refuses to start without it.
  3. Set SECURE_COOKIE=true when the instance is served over HTTPS.
  4. Restart the instance and add a provider. A super admin opens Access > SAML SSO in the admin console and chooses New provider, or uses the API below.
  5. Give your provider the addresses in Register LyEve with the provider.

On an instance with several tenants, the sign-in routes take the tenant from the domain the request arrives on. Map a domain to each tenant that uses SAML. See tenants.

You need a super admin token in TOKEN. The quickstart shows how to get one.

  1. List the templates:

    Terminal window
    curl http://localhost:3001/api/admin/saml-templates \
    -H "Authorization: Bearer $TOKEN"
    [
    { "key": "okta", "name": "Okta", "description": "Okta Workforce Identity Cloud SAML 2.0 integration." },
    { "key": "azure-ad", "name": "Azure AD / Entra ID", "description": "Microsoft Azure Active Directory / Entra ID SAML 2.0 integration." },
    { "key": "onelogin", "name": "OneLogin", "description": "OneLogin SAML 2.0 SSO integration." }
    ]
  2. Read the settings Okta expects. Nothing is saved:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/saml-templates/apply \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"key": "okta"}'

    The answer holds key, name, description and a config with the signature settings, the attribute mapping and an idp_cert_hint saying where Okta shows its certificate.

  3. Create the provider with the values from Okta:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/saml-providers \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
    "name": "okta",
    "entity_id": "http://www.okta.com/exk1a2b3c4d5e6f7g8h9",
    "sso_url": "https://example.okta.com/app/example_lyeve/exk1a2b3c4d5e6f7g8h9/sso/saml",
    "idp_cert": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----",
    "attributes_mapping": {"email": "email", "roles": "groups"},
    "enabled": true
    }'

    The answer is 201 with the provider, its sp_cert_active, and sp_cert_expires_at and idp_cert_expires_at. Copy id into PROVIDER_ID.

  4. Fetch the metadata to give Okta:

    Terminal window
    curl http://localhost:3001/api/admin/auth/saml/okta/metadata

    The answer is the service provider's metadata XML.

  5. Open Access > SAML SSO in the admin console. The provider is listed with its certificate expiry dates, and the login page offers it.

For a provider named okta, give your identity provider:

Setting at the providerValue
Assertion consumer service (ACS) URL{LYEVE_BASE_URL}/api/admin/auth/saml/okta/acs
SP entity ID (audience)The same ACS URL
SP metadata{LYEVE_BASE_URL}/api/admin/auth/saml/okta/metadata

Many providers read everything from the metadata URL. The provider must send the user's email in the attribute named in attributes_mapping.email.

To sign in, send the browser to /api/admin/auth/saml/okta. Add ?redirect=/admin/content to land on another page of the console afterwards. Only a path on the same site is accepted.

Provider fields
FieldMeaningDefault
nameUsed in the sign-in URL. Unique in the tenantrequired
entity_idThe provider's entity IDrequired
sso_urlThe provider's single sign-on URLrequired
slo_urlThe provider's single logout URLnone
idp_certThe provider's signing certificate, PEM. Never returnedrequired
name_id_formatThe NameID format to requesturn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
attributes_mappingWhich assertion attributes hold the email and the roles{"email": "email", "roles": "groups"}
want_assertions_signed, want_response_signed, sign_authn_requestsSignature requirements. A new provider always starts with all three ontrue
want_authn_signed, encrypt_assertionsFurther signature and encryption optionsfalse
enabledWhether the login page offers itfalse

Rotate in two steps so sign-in never breaks:

  1. Stage a new certificate. The answer shows it as sp_cert_next, and the metadata then lists both certificates:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/saml-providers/$PROVIDER_ID/prepare-cert \
    -H "Authorization: Bearer $TOKEN"
  2. Wait until the provider has read the new metadata, or upload the new certificate there by hand. Then promote it:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/saml-providers/$PROVIDER_ID/rollover-cert \
    -H "Authorization: Bearer $TOKEN"

Both calls return the provider. Promoting before staging answers 400 no next certificate configured. The console shows the same two steps, and counts the certificates that are expired or close to expiry under Certificates to renew.

VariableWhat it doesDefault
LYEVE_BASE_URLPublic address the ACS and metadata URLs are built from. Required when APP_ENV is production.unset
APP_ENVOutside production, a missing LYEVE_BASE_URL falls back to the request's host.production
SECURE_COOKIEMarks the sign-in cookies Secure.false
JWT_EXPIRY_SECSLifetime of the session a sign-in creates.900

If you set LYEVE_PLUGINS, include saml in it.

Every route that needs a role takes a signed-in session. An admin token is refused on them with 403.

Sign-in, providers and templates
MethodPathRolePurpose
GET/api/admin/auth/saml-providerspublicNames of enabled providers, for login buttons
GET/api/admin/auth/saml/{provider}publicStart sign-in. Redirects to the provider
POST/api/admin/auth/saml/{provider}/acspublicWhere the provider posts its answer
GET/api/admin/auth/saml/{provider}/metadatapublicLyEve's metadata XML for that provider
GET/api/admin/saml-providersadminList providers, including disabled ones
POST/api/admin/saml-providerssuper_adminAdd a provider. 201
PUT/api/admin/saml-providers/{id}super_adminChange a provider
DELETE/api/admin/saml-providers/{id}super_adminRemove a provider. 204
POST/api/admin/saml-providers/{id}/prepare-certsuper_adminStage a new signing certificate
POST/api/admin/saml-providers/{id}/rollover-certsuper_adminPromote the staged certificate
GET/api/admin/saml-templatesadminList the templates
GET/api/admin/saml-templates/{key}adminRead one template
POST/api/admin/saml-templates/applysuper_adminReturn a template's settings without saving anything
StatusMessageCause
404provider not foundNo enabled provider of that name in the tenant.
401SAML authentication failedThe answer did not verify, or LyEve did not ask for it.
409assertion already consumedThe same assertion was sent twice.
401identity provider did not provide an email addressThe email attribute is missing.
Every other error
StatusMessageCause
401authentication failedThe account is disabled or expired.
400no next certificate configuredrollover-cert was called before prepare-cert.
400key is requiredapply was called without a template key.
404template not foundNo template has that key.
415unsupported media type, expected application/json or multipart/form-dataA body in any other format.
404The requested endpoint does not exist.The instance started without a license that carries saml.
402payment_requiredThe license stopped carrying saml while the instance was running.
  • Sign-in fails right after the provider's login page. Check that the ACS URL and entity ID at the provider match the table above, and that LYEVE_BASE_URL is the address users reach.
  • Users land without the roles they expect. Check attributes_mapping.roles against the attribute your provider sends. An existing account keeps its LyEve roles. admin and super_admin are never taken from the provider, so grant them in LyEve.