# SSO Providers Mosaic Stack supports optional enterprise single sign-on through Better Auth's generic OAuth flow. The gateway mounts Better Auth under `/api/auth`, so every provider callback terminates at: ```text {BETTER_AUTH_URL}/api/auth/oauth2/callback/{providerId} ``` For the providers in this document: - Authentik: `{BETTER_AUTH_URL}/api/auth/oauth2/callback/authentik` - WorkOS: `{BETTER_AUTH_URL}/api/auth/oauth2/callback/workos` - Keycloak: `{BETTER_AUTH_URL}/api/auth/oauth2/callback/keycloak` ## Required environment variables ### Authentik ```bash AUTHENTIK_ISSUER=https://auth.example.com/application/o/mosaic AUTHENTIK_CLIENT_ID=... AUTHENTIK_CLIENT_SECRET=... ``` ### WorkOS ```bash WORKOS_ISSUER=https://your-company.authkit.app WORKOS_CLIENT_ID=client_... WORKOS_CLIENT_SECRET=... NEXT_PUBLIC_WORKOS_ENABLED=true ``` `WORKOS_ISSUER` should be the WorkOS AuthKit issuer or custom auth domain, not the raw REST API hostname. Mosaic derives the OIDC discovery URL from that issuer. ### Keycloak ```bash KEYCLOAK_ISSUER=https://auth.example.com/realms/master KEYCLOAK_CLIENT_ID=mosaic KEYCLOAK_CLIENT_SECRET=... NEXT_PUBLIC_KEYCLOAK_ENABLED=true ``` If you prefer, you can keep the issuer split as: ```bash KEYCLOAK_URL=https://auth.example.com KEYCLOAK_REALM=master ``` The auth package will derive `KEYCLOAK_ISSUER` from those two values. ## WorkOS setup 1. In WorkOS, create or select the application that will back Mosaic login. 2. Configure an AuthKit domain or custom authentication domain for the application. 3. Add the redirect URI: ```text {BETTER_AUTH_URL}/api/auth/oauth2/callback/workos ``` 4. Copy the application's `client_id` and `client_secret` into `WORKOS_CLIENT_ID` and `WORKOS_CLIENT_SECRET`. 5. Set `WORKOS_ISSUER` to the AuthKit domain from step 2. 6. Create the WorkOS organization and attach the enterprise SSO connection you want Mosaic to use. 7. Set `NEXT_PUBLIC_WORKOS_ENABLED=true` in the web deployment so the login button is rendered. ## Keycloak setup 1. Start from an existing Keycloak realm or create a dedicated realm for Mosaic. 2. Create a confidential OIDC client named `mosaic` or your preferred client ID. 3. Set the valid redirect URI to: ```text {BETTER_AUTH_URL}/api/auth/oauth2/callback/keycloak ``` 4. Set the web origin to the public Mosaic web URL. 5. Copy the client secret into `KEYCLOAK_CLIENT_SECRET`. 6. Set either `KEYCLOAK_ISSUER` directly or `KEYCLOAK_URL` + `KEYCLOAK_REALM`. 7. Set `NEXT_PUBLIC_KEYCLOAK_ENABLED=true` in the web deployment so the login button is rendered. ### Local Keycloak smoke test If you want to test locally with Docker: ```bash docker run --rm --name mosaic-keycloak \ -p 8080:8080 \ -e KEYCLOAK_ADMIN=admin \ -e KEYCLOAK_ADMIN_PASSWORD=admin \ quay.io/keycloak/keycloak:26.1 start-dev ``` Then configure: ```bash KEYCLOAK_ISSUER=http://localhost:8080/realms/master KEYCLOAK_CLIENT_ID=mosaic KEYCLOAK_CLIENT_SECRET=... NEXT_PUBLIC_KEYCLOAK_ENABLED=true ``` ## Web flow The web login page renders provider buttons from `NEXT_PUBLIC_*_ENABLED` flags. Each button links to `/auth/provider/{providerId}`, and that page initiates Better Auth's `signIn.oauth2` flow before handing off to the provider. ## Failure mode Provider config is optional, but partial config is rejected at startup. If any provider-specific env var is present without the full required set, `@mosaic/auth` throws a bootstrap error with the missing keys instead of silently registering a broken provider.