3.4 KiB
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:
{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
AUTHENTIK_ISSUER=https://auth.example.com/application/o/mosaic
AUTHENTIK_CLIENT_ID=...
AUTHENTIK_CLIENT_SECRET=...
WorkOS
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
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:
KEYCLOAK_URL=https://auth.example.com
KEYCLOAK_REALM=master
The auth package will derive KEYCLOAK_ISSUER from those two values.
WorkOS setup
- In WorkOS, create or select the application that will back Mosaic login.
- Configure an AuthKit domain or custom authentication domain for the application.
- Add the redirect URI:
{BETTER_AUTH_URL}/api/auth/oauth2/callback/workos
- Copy the application's
client_idandclient_secretintoWORKOS_CLIENT_IDandWORKOS_CLIENT_SECRET. - Set
WORKOS_ISSUERto the AuthKit domain from step 2. - Create the WorkOS organization and attach the enterprise SSO connection you want Mosaic to use.
- Set
NEXT_PUBLIC_WORKOS_ENABLED=truein the web deployment so the login button is rendered.
Keycloak setup
- Start from an existing Keycloak realm or create a dedicated realm for Mosaic.
- Create a confidential OIDC client named
mosaicor your preferred client ID. - Set the valid redirect URI to:
{BETTER_AUTH_URL}/api/auth/oauth2/callback/keycloak
- Set the web origin to the public Mosaic web URL.
- Copy the client secret into
KEYCLOAK_CLIENT_SECRET. - Set either
KEYCLOAK_ISSUERdirectly orKEYCLOAK_URL+KEYCLOAK_REALM. - Set
NEXT_PUBLIC_KEYCLOAK_ENABLED=truein the web deployment so the login button is rendered.
Local Keycloak smoke test
If you want to test locally with Docker:
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:
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.