193 lines
8.4 KiB
Markdown
193 lines
8.4 KiB
Markdown
---
|
|
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)
|