diff --git a/docs/auth.md b/docs/auth.md index d3b4d38ba0..33e7b81fe0 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -130,7 +130,9 @@ For more information on setting up the OIDC auth provider, consult the [Backstag ### Sign In Page configuration value -After selecting the authentication provider you wish to use with your RHDH instance, ensure to add the `signInPage` configuration value to ensure that the frontend displays the appropriate authentication provider. +After selecting the authentication provider(s) you wish to use with your RHDH instance, add the `signInPage` configuration value to ensure that the frontend displays the appropriate authentication provider(s). + +#### Single provider - Add the corresponding Authentication provider key as the value to `signInPage` in your `app-config`. Where `provider-id` matches the chosen provider from the table above. @@ -138,6 +140,21 @@ After selecting the authentication provider you wish to use with your RHDH insta signInPage: ``` +#### Multiple providers + +- To allow users to authenticate with multiple auth providers, you can specify a list of provider IDs: + + ```yaml + signInPage: + - github + - microsoft + - oidc + ``` + + This will display a sign-in page with buttons for each of the specified authentication providers, allowing users to choose their preferred method of authentication. + + **Note:** If any of the specified providers is a proxied provider (e.g., `oauth2Proxy`), only the first proxied provider will be used and a proxied sign-in page will be displayed instead. + ### Enabling/Disabling the guest provider and login The guest login is provided by a special authentication provider that must be explicitly enabled. This authentication provider should be used for development purposes only and is not intended for production, as it creates a default user that has user-level access to the Backstage instance. diff --git a/packages/app/config.d.ts b/packages/app/config.d.ts index 97506684bd..78eb4828d9 100644 --- a/packages/app/config.d.ts +++ b/packages/app/config.d.ts @@ -270,7 +270,7 @@ export interface Config { * The signInPage provider * @visibility frontend */ - signInPage?: string; + signInPage?: string | string[]; /** * The option to includes transient parent groups when determining user group membership * @visibility frontend diff --git a/packages/app/src/components/SignInPage/SignInPage.tsx b/packages/app/src/components/SignInPage/SignInPage.tsx index 6727b96329..e541325b19 100644 --- a/packages/app/src/components/SignInPage/SignInPage.tsx +++ b/packages/app/src/components/SignInPage/SignInPage.tsx @@ -156,27 +156,46 @@ export function SignInPage(props: SignInPageProps): React.JSX.Element { const configApi = useApi(configApiRef); const { t } = useTranslation(); const isDevEnv = configApi.getString('auth.environment') === 'development'; - const provider = - configApi.getOptionalString('signInPage') ?? DEFAULT_PROVIDER; - const providers = createProviders(t); - const providerConfig = - providers.get(provider) ?? providers.get(DEFAULT_PROVIDER)!; + const signInPageConfig = configApi.getOptional( + 'signInPage', + ); + const configValue = signInPageConfig ?? DEFAULT_PROVIDER; + const providerNames = Array.isArray(configValue) + ? configValue + : [configValue]; - if (typeof providerConfig === 'object') { - const providerList = isDevEnv - ? (['guest', providerConfig] satisfies ['guest', SignInProviderConfig]) - : [providerConfig]; + const providers = createProviders(t); - return ( - + const providerConfigs = providerNames + .map(name => providers.get(name)) + .filter( + (config): config is SignInProviderConfig | string => config !== undefined, ); + + if (providerConfigs.length === 0) { + const defaultProvider = providers.get(DEFAULT_PROVIDER); + if (defaultProvider) providerConfigs.push(defaultProvider); } - return ; + // If any provider is proxied (i.e. does not use SignInProviderConfig), use the first proxied provider + if (providerConfigs.some(config => typeof config === 'string')) { + const proxiedProvider = providerConfigs.find( + config => typeof config === 'string', + ) as string; + return ; + } + + const providerList = isDevEnv + ? ['guest' as const, ...(providerConfigs as SignInProviderConfig[])] + : (providerConfigs as SignInProviderConfig[]); + + return ( + + ); }