Configure single sign-on (SAML / OIDC)
PLACEHOLDER Cloud supports SAML 2.0 and OpenID Connect identity providers. Members of your org sign in via your IdP; users are JIT-provisioned (just-in-time created) the first time they log in.
Goal
Wire one of your identity providers — Okta, Azure AD, Google Workspace, etc. — to PLACEHOLDER Cloud, sign in with a corporate identity, and (optionally) disable the email + password login path for your org.
Prereqs
- Org-owner role in PLACEHOLDER Cloud.
- A running PLACEHOLDER Cloud with
PUBLIC_BASE_URLset to the public hostname your IdP will redirect to (e.g.https://dq.example.com). The callback URL is built from this — see Configuration. - For OIDC: the IdP's issuer URL, client ID, and client secret.
- For SAML: the IdP's entity ID, single-sign-on (SSO) URL, and the X.509 certificate that signs assertions.
How secrets are stored
Client secrets and IdP private keys are encrypted at rest under your org's data-encryption key. The encryption envelope is HARDEN-16: each org owns a Data Encryption Key (DEK) which is itself wrapped under the Key Encryption Key (KEK) configured for the deployment. A leaked DB backup never exposes IdP secrets unless the KEK leaks too.
The UI list view replaces ciphertext fields with <field>_set: true markers; the secret never round-trips through the browser after it's saved.
Add an OIDC provider
Pick a provider template
Settings → Single sign-on → Add provider opens with a Provider picker offering Okta, Microsoft Entra ID, Google Workspace, SAML (custom), and OIDC (custom).
Pick a named provider and the modal:
- sets the kind to OIDC,
- prefills the issuer — a fixed value for Google Workspace (
https://accounts.google.com), or swaps the placeholder to that provider's issuer pattern for Okta (https://{your-domain}.okta.com/oauth2/default) and Entra ID (https://login.microsoftonline.com/{tenant-id}/v2.0), and - shows provider-specific step-by-step setup hints plus a link to that IdP's admin console.
Once the issuer is filled, click Discover as usual to resolve the concrete OIDC endpoints from the well-known document (see the per-provider sub-sections below). Choosing OIDC (custom) or SAML (custom) skips the templated guidance and gives you the plain form. The default selection is OIDC (custom).
Google Workspace SSO is configured here, in the SSO settings, using
https://accounts.google.comas the issuer — the same place as every other OIDC provider.
Okta
- In Okta, Applications → Create App Integration → OIDC, Web app.
- Sign-in redirect URI:
https://dq.example.com/auth/sso/<your-org-slug>/callback. - Sign-out redirect URI:
https://dq.example.com/login. - Copy the Client ID, Client secret, and Okta domain (the issuer is
https://<domain>).
Azure AD
- In the Azure portal, App registrations → New registration.
- Redirect URI:
https://dq.example.com/auth/sso/<your-org-slug>/callback(Web). - Certificates & secrets → New client secret, copy it.
- The issuer URL is
https://login.microsoftonline.com/<tenant-id>/v2.0.
Google Workspace
- Cloud Console → APIs & Services → Credentials → OAuth client ID.
- Application type: Web; authorised redirect URI:
https://dq.example.com/auth/sso/<your-org-slug>/callback. - The issuer URL is
https://accounts.google.com. - Copy the client ID + secret.
In PLACEHOLDER Cloud
- Settings → Single sign-on → Add provider.
- Provider: pick Okta, Microsoft Entra ID, or Google Workspace (or OIDC (custom) for any other OIDC IdP). This sets the kind to OIDC and prefills the issuer.
- Paste / confirm the issuer URL, then client ID and client secret.
- Choose the default role for JIT-provisioned users (
vieweris safest; bump them up once you've confirmed they're in the right org). - Leave Enforce unchecked the first time — that way you can still fall back to password login if the IdP config has a typo.
- Save.
Add a SAML provider
Note: SAML support is an optional install. Self-hosted deploys need the
dq-cloud-api[saml]extra (which depends onpython3-saml, which in turn depends on thelibxml2/xmlsecsystem libraries). If the extra isn't installed, the SAML endpoints return HTTP 501 with a clear install hint and OIDC continues to work.
Okta
- Applications → Create App Integration → SAML 2.0.
- Single sign-on URL (ACS):
https://dq.example.com/auth/sso/<your-org-slug>/callback. - Audience URI (SP entity ID):
https://dq.example.com. - After saving, View setup instructions gives you the IdP's SSO URL, Entity ID, and X.509 certificate.
In PLACEHOLDER Cloud
- Settings → Single sign-on → Add provider.
- Kind: SAML.
- Paste the entity ID, SSO URL, and the IdP's X.509 certificate (
-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----). - (Optional) Paste the full metadata XML if you'd like the toolkit to discover the SSO endpoints by itself.
- Pick a default role and Save.
Test the login flow
- Open
https://dq.example.com/loginin an incognito window. - Click Sign in with SSO.
- Type your org slug. PLACEHOLDER Cloud redirects you to the IdP; complete the IdP's login.
- The IdP bounces you back to
/auth/sso/<slug>/callback. You should land in the PLACEHOLDER Cloud home page, signed in.
A first-time SSO login creates a users row with hashed_password = NULL and external_identity = {idp_id, subject}. Subsequent logins look the user up by (idp_id, subject) directly.
Enforce SSO
Once SSO is working, edit the provider and tick Enforce. Password login for any member of your org will then return HTTP 403 with code: sso_required and point the caller at the SSO start endpoint.
Tip: don't enforce until you have at least one org owner who has successfully completed an SSO login. The login page falls back to the password form for non-owner roles, but enforcement disables it across the board.
Troubleshooting
| Symptom | Likely cause |
|---|---|
OIDC discovery failed: HTTP 404 | Wrong issuer URL — confirm https://<issuer>/.well-known/openid-configuration returns 200 from the API host. |
ID token verification failed: Invalid audience | Client ID in PLACEHOLDER Cloud doesn't match the one configured at the IdP. |
ID token nonce mismatch | The IdP didn't echo the nonce. Confirm you're using the authorization-code flow (not implicit). |
State expired or unknown | The user took > 5 minutes between /start and the IdP callback, or the state was already consumed. Have them retry. |
SAML response invalid: ... | The IdP's X.509 certificate in PLACEHOLDER Cloud doesn't match the one that signed the assertion. Re-copy from the IdP. |
| 501 on a SAML endpoint | python3-saml isn't installed. pip install 'dq-cloud-api[saml]' and restart the API. |
Related
- Multi-tenancy concept — orgs, workspaces, roles.
- Configuration reference —
PUBLIC_BASE_URL,ENCRYPTION_KEY,ENCRYPTION_KMS_KEY_ID. - HARDEN-16 — encryption envelope for IdP secrets.