docs: migrate SSO provider runbook
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
---
|
||||
title: SSO Providers
|
||||
type: runbook
|
||||
audience: admin
|
||||
status: current
|
||||
source_of_truth: false
|
||||
---
|
||||
|
||||
# SSO Providers
|
||||
|
||||
Configure optional enterprise single sign-on for Mosaic Stack through Better Auth's generic OAuth integration. The gateway owns provider configuration and discovery; the web application renders only providers reported by the gateway.
|
||||
|
||||
> **Current behavior:** Authentik, WorkOS, and Keycloak are supported in the checked-in implementation. Authentik and WorkOS use OIDC. Keycloak supports OIDC and an optional direct SAML login URL. The web application does **not** read `NEXT_PUBLIC_WORKOS_ENABLED` or `NEXT_PUBLIC_KEYCLOAK_ENABLED`; provider buttons are discovered dynamically from the gateway.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before configuring a provider, establish these gateway settings:
|
||||
|
||||
- `BETTER_AUTH_URL` — the public base URL used to construct OAuth callback URLs.
|
||||
- `BETTER_AUTH_SECRET` — a strong secret for Better Auth sessions and tokens.
|
||||
- `GATEWAY_CORS_ORIGIN` — the web origin or comma-separated origins allowed by the gateway.
|
||||
|
||||
Keep client secrets and Better Auth secrets in the deployment secret store. Do not commit them to `.env` files or expose them to the web bundle.
|
||||
|
||||
## Provider configuration
|
||||
|
||||
### Authentik OIDC
|
||||
|
||||
Set all three variables to enable Authentik:
|
||||
|
||||
```bash
|
||||
AUTHENTIK_ISSUER=https://auth.example.com/application/o/mosaic
|
||||
AUTHENTIK_CLIENT_ID=...
|
||||
AUTHENTIK_CLIENT_SECRET=...
|
||||
```
|
||||
|
||||
The implementation derives OIDC discovery and endpoint URLs from `AUTHENTIK_ISSUER`. An optional team-claim label can be exposed in provider discovery:
|
||||
|
||||
```bash
|
||||
AUTHENTIK_TEAM_SYNC_CLAIM=groups
|
||||
```
|
||||
|
||||
The default reported claim is `groups`. The discovery payload reports this claim; verify any downstream membership-sync behavior separately before treating it as an authorization guarantee.
|
||||
|
||||
Register this redirect URI with the Authentik application:
|
||||
|
||||
```text
|
||||
{BETTER_AUTH_URL}/api/auth/oauth2/callback/authentik
|
||||
```
|
||||
|
||||
### WorkOS OIDC
|
||||
|
||||
Set all three variables to enable WorkOS:
|
||||
|
||||
```bash
|
||||
WORKOS_ISSUER=https://your-company.authkit.app
|
||||
WORKOS_CLIENT_ID=client_...
|
||||
WORKOS_CLIENT_SECRET=...
|
||||
```
|
||||
|
||||
Use the WorkOS AuthKit issuer or custom authentication domain, not a raw WorkOS REST API hostname. Mosaic derives the OIDC discovery URL by appending `/.well-known/openid-configuration` to the issuer. WorkOS uses PKCE and issuer validation in the current auth configuration.
|
||||
|
||||
An optional team-claim label can be exposed in provider discovery:
|
||||
|
||||
```bash
|
||||
WORKOS_TEAM_SYNC_CLAIM=organization_id
|
||||
```
|
||||
|
||||
The default reported claim is `organization_id`. The discovery payload reports this claim; verify any downstream membership-sync behavior separately before treating it as an authorization guarantee.
|
||||
|
||||
Register this redirect URI with the WorkOS application:
|
||||
|
||||
```text
|
||||
{BETTER_AUTH_URL}/api/auth/oauth2/callback/workos
|
||||
```
|
||||
|
||||
### Keycloak OIDC
|
||||
|
||||
Use either an explicit issuer or the URL-plus-realm form. The client ID and secret are required in both forms.
|
||||
|
||||
Explicit issuer:
|
||||
|
||||
```bash
|
||||
KEYCLOAK_ISSUER=https://auth.example.com/realms/mosaic
|
||||
KEYCLOAK_CLIENT_ID=mosaic
|
||||
KEYCLOAK_CLIENT_SECRET=...
|
||||
```
|
||||
|
||||
Derived issuer:
|
||||
|
||||
```bash
|
||||
KEYCLOAK_URL=https://auth.example.com
|
||||
KEYCLOAK_REALM=mosaic
|
||||
KEYCLOAK_CLIENT_ID=mosaic
|
||||
KEYCLOAK_CLIENT_SECRET=...
|
||||
```
|
||||
|
||||
`KEYCLOAK_ISSUER` takes precedence when both forms are present. Keycloak uses PKCE and issuer validation in the current auth configuration.
|
||||
|
||||
An optional team-claim label can be exposed in provider discovery:
|
||||
|
||||
```bash
|
||||
KEYCLOAK_TEAM_SYNC_CLAIM=groups
|
||||
```
|
||||
|
||||
The default reported claim is `groups`. The discovery payload reports this claim; verify any downstream membership-sync behavior separately before treating it as an authorization guarantee.
|
||||
|
||||
Register this redirect URI with the Keycloak client:
|
||||
|
||||
```text
|
||||
{BETTER_AUTH_URL}/api/auth/oauth2/callback/keycloak
|
||||
```
|
||||
|
||||
### Keycloak direct SAML fallback
|
||||
|
||||
The current web flow supports a direct SAML link for Keycloak when `KEYCLOAK_SAML_LOGIN_URL` is configured:
|
||||
|
||||
```bash
|
||||
KEYCLOAK_SAML_LOGIN_URL=https://auth.example.com/realms/mosaic/protocol/saml
|
||||
```
|
||||
|
||||
This creates a configured Keycloak provider with `loginMode: saml`. The web login button links directly to the supplied URL as `Continue with Keycloak (SAML)`; there is no Better Auth OIDC callback for this mode. The URL must be the provider's valid SAML launch URL for the deployment.
|
||||
|
||||
A SAML-only Keycloak configuration does not require the Keycloak OIDC client variables. Do not combine an incomplete OIDC variable set with SAML-only configuration: partial OIDC configuration is rejected during auth setup.
|
||||
|
||||
## Callback and discovery contract
|
||||
|
||||
Better Auth is mounted at `/api/auth`. OIDC callbacks use:
|
||||
|
||||
```text
|
||||
{BETTER_AUTH_URL}/api/auth/oauth2/callback/{providerId}
|
||||
```
|
||||
|
||||
The gateway exposes provider discovery at:
|
||||
|
||||
```text
|
||||
GET /api/sso/providers
|
||||
```
|
||||
|
||||
The response includes `authentik`, `workos`, and `keycloak` records with:
|
||||
|
||||
- `configured` — whether a usable OIDC or Keycloak SAML configuration is present.
|
||||
- `protocols` — supported protocols for the provider record.
|
||||
- `loginMode` — `oidc`, `saml`, or `null`.
|
||||
- `callbackPath` — the OIDC callback path, or `null` for SAML-only mode.
|
||||
- `teamSync` — the configured/default claim label exposed to the UI.
|
||||
- `samlFallback` — whether a direct Keycloak SAML URL is configured.
|
||||
- `warnings` — partial OIDC configuration warnings when reported.
|
||||
|
||||
The web login page filters this response to configured providers. OIDC buttons use Better Auth's `signIn.oauth2` flow. A configured Keycloak SAML fallback is rendered as a direct link. No provider-specific `NEXT_PUBLIC_*_ENABLED` flag is required or consumed.
|
||||
|
||||
## Configuration procedure
|
||||
|
||||
1. Set `BETTER_AUTH_URL` to the public gateway URL that the identity provider can reach.
|
||||
2. Set `BETTER_AUTH_SECRET` and the correct `GATEWAY_CORS_ORIGIN` values.
|
||||
3. Choose one provider configuration above and set its complete required variable group.
|
||||
4. Register the exact OIDC callback URI with the identity provider, when using OIDC.
|
||||
5. Restart or redeploy the gateway so it loads the changed environment.
|
||||
6. Inspect discovery without exposing secrets:
|
||||
|
||||
```bash
|
||||
curl "$BETTER_AUTH_URL/api/sso/providers"
|
||||
```
|
||||
|
||||
7. Open the web login page and confirm that only configured providers are shown.
|
||||
8. Complete a sign-in and verify the callback returns to the configured application.
|
||||
|
||||
## Partial configuration and failure modes
|
||||
|
||||
Provider configuration is optional. If no provider variables are set, the gateway can run without SSO providers and the web login page renders no SSO section.
|
||||
|
||||
For Authentik and WorkOS, setting only part of the issuer/client ID/client secret group raises a configuration error. For Keycloak OIDC, the client ID, client secret, and either an explicit issuer or a complete URL-plus-realm pair are required. Empty or whitespace-only values are treated as unset.
|
||||
|
||||
Common failures:
|
||||
|
||||
| Symptom | Check |
|
||||
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| Provider does not appear on the login page | Query `/api/sso/providers`; verify the complete provider variable group is present in the gateway environment. |
|
||||
| OAuth callback is rejected | Compare the registered redirect URI character-for-character with `BETTER_AUTH_URL` and the provider callback path. |
|
||||
| Provider is shown but sign-in cannot start | Check `loginMode`, issuer discovery, client credentials, and gateway logs. |
|
||||
| Keycloak SAML button is absent | Set `KEYCLOAK_SAML_LOGIN_URL` to the provider's direct launch URL and reload the gateway. |
|
||||
| Startup/auth initialization reports missing variables | Remove the partial provider configuration or provide the complete required group. |
|
||||
| SSO succeeds but team membership is unexpected | Treat `teamSync.claim` as discovery metadata and verify the actual claim mapping and membership-sync implementation. |
|
||||
|
||||
Do not enable a provider by adding the obsolete `NEXT_PUBLIC_WORKOS_ENABLED` or `NEXT_PUBLIC_KEYCLOAK_ENABLED` variables. They are not read by the current web application.
|
||||
|
||||
## Related
|
||||
|
||||
- [Administrator guide](../README.md)
|
||||
- [Security chapter](README.md)
|
||||
- [API documentation index](../../API/README.md)
|
||||
- [Documentation atlas](../../README.md)
|
||||
Reference in New Issue
Block a user