diff --git a/packages/auth/src/sso.ts b/packages/auth/src/sso.ts index 00fb307..1da3649 100644 --- a/packages/auth/src/sso.ts +++ b/packages/auth/src/sso.ts @@ -62,6 +62,13 @@ function buildAuthentikConfig(env: EnvMap): GenericOidcProviderConfig | null { const clientId = readEnv(env, 'AUTHENTIK_CLIENT_ID'); const clientSecret = readEnv(env, 'AUTHENTIK_CLIENT_SECRET'); + const fields = [issuer, clientId, clientSecret]; + const presentCount = fields.filter(Boolean).length; + if (presentCount > 0 && presentCount < fields.length) { + throw new Error( + '@mosaic/auth: Authentik SSO requires AUTHENTIK_ISSUER, AUTHENTIK_CLIENT_ID, AUTHENTIK_CLIENT_SECRET.', + ); + } if (!issuer || !clientId || !clientSecret) { return null; } @@ -86,6 +93,13 @@ function buildWorkosConfig(env: EnvMap): GenericOidcProviderConfig | null { const clientId = readEnv(env, 'WORKOS_CLIENT_ID'); const clientSecret = readEnv(env, 'WORKOS_CLIENT_SECRET'); + const fields = [issuer, clientId, clientSecret]; + const presentCount = fields.filter(Boolean).length; + if (presentCount > 0 && presentCount < fields.length) { + throw new Error( + '@mosaic/auth: WorkOS SSO requires WORKOS_ISSUER, WORKOS_CLIENT_ID, WORKOS_CLIENT_SECRET.', + ); + } if (!issuer || !clientId || !clientSecret) { return null; } @@ -105,10 +119,25 @@ function buildWorkosConfig(env: EnvMap): GenericOidcProviderConfig | null { } function buildKeycloakConfig(env: EnvMap): GenericOidcProviderConfig | null { - const issuer = readEnv(env, 'KEYCLOAK_ISSUER'); + const explicitIssuer = readEnv(env, 'KEYCLOAK_ISSUER'); + const keycloakUrl = readEnv(env, 'KEYCLOAK_URL'); + const keycloakRealm = readEnv(env, 'KEYCLOAK_REALM'); const clientId = readEnv(env, 'KEYCLOAK_CLIENT_ID'); const clientSecret = readEnv(env, 'KEYCLOAK_CLIENT_SECRET'); + // Derive issuer from KEYCLOAK_URL + KEYCLOAK_REALM if KEYCLOAK_ISSUER not set + const issuer = + explicitIssuer ?? + (keycloakUrl && keycloakRealm + ? `${keycloakUrl.replace(/\/$/, '')}/realms/${keycloakRealm}` + : undefined); + + const anySet = !!(issuer || clientId || clientSecret); + if (anySet && (!issuer || !clientId || !clientSecret)) { + throw new Error( + '@mosaic/auth: Keycloak SSO requires KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, KEYCLOAK_ISSUER.', + ); + } if (!issuer || !clientId || !clientSecret) { return null; }