Backstage is an excellent dashboard tool for developers. Its plugin system makes it particularly flexible. However, configuring these plugins can be tedious. Backstage is constantly evolving, which sometimes makes it difficult for the documentation to keep up. This has been the case since the migration to the new Backend system. Backstage provides several plugins for connecting to most identity providers via OIDC. However, if you want to connect Backstage to a custom provider, like an enterprise Keycloak, the documentation is not very clear. That’s what we will explore in this post.
OIDC plugin configuration
Backstage provides an OIDC provider but no ready-to-use plugin. We will need to create a module to extend Backstage’s Auth plugin with our OIDC support. We use the Backstage CLI for this:
backstage-cli new --select backend-module
# ? Enter the ID of the plugin [required] : auth# ? Enter the ID of the module [required] : oidc
Backstage has now generated a plugin structure in the plugins/auth-backend-module-oidc folder. Let’s start by adding the OIDC provider dependency provided by Backstage:
import{oidcAuthenticator}from'@backstage/plugin-auth-backend-module-oidc-provider';import{authProvidersExtensionPoint,createOAuthProviderFactory}from'@backstage/plugin-auth-node'import{coreServices,createBackendModule,}from'@backstage/backend-plugin-api';import{DEFAULT_NAMESPACE,stringifyEntityRef}from'@backstage/catalog-model';exportconstauthModuleOidc=createBackendModule({pluginId:'auth',moduleId:'oidc',register(reg){reg.registerInit({deps:{logger: coreServices.logger,providers: authProvidersExtensionPoint},asyncinit({logger,providers}){logger.info('Registering OIDC provider!');providers.registerProvider({providerId:'sso-auth-provider',factory: createOAuthProviderFactory({authenticator: oidcAuthenticator,asyncsignInResolver(info,ctx){constuserRef=stringifyEntityRef({kind:'User',name: info.result.fullProfile.userinfo.sub,namespace:DEFAULT_NAMESPACE});returnctx.issueToken({claims:{sub: userRef,// The user's own identity
ent:[userRef],// A list of identities that the user claims ownership through
}});}})});},});},});
Our module is now operational. Let’s check that the module is properly enabled in packages/backend/index.ts. The following line should be present:
import{AnyApiFactory,ApiRef,BackstageIdentityApi,configApiRef,createApiFactory,createApiRef,discoveryApiRef,oauthRequestApiRef,OpenIdConnectApi,ProfileInfoApi,SessionApi,}from'@backstage/core-plugin-api';import{OAuth2}from'@backstage/core-app-api';exportconstoidcAuthApiRef: ApiRef<OpenIdConnectApi&// The OIDC API that will handle authentification
ProfileInfoApi&// Profile API for requesting user profile info from the auth provider in question
BackstageIdentityApi&// Backstage Identity API to handle and associate the user profile with backstage identity
SessionApi// Sesssion API, to handle the session the user will have while logged in
>=createApiRef({id:'sso-auth-provider'// Can be anything as long as it doesn't conflict with other API ref IDs
})exportconstapis: AnyApiFactory[]=[createApiFactory({api: oidcAuthApiRef,deps:{discoveryApi: discoveryApiRef,oauthRequestApi: oauthRequestApiRef,configApi: configApiRef},factory:({discoveryApi,oauthRequestApi,configApi})=>Oauth2.create({configApi,discoveryApi,oauthRequestApi,provider:{id:'sso-auth-provider',title:'Enterprise SSO',icon:()=>null},environment: configApi.getOptionalString('auth.environment'),defaultScopes:['openId','profile','email'],popupOptions:{size:{// fullscreen: true
// or specify popup width and height
width: 1000,height: 1000,}}})}),// Other createApiFactory
]
Adding the connection button into the interface
Now let’s go to the packages/app/src/App.tsx file to add the login button to Backstage.
import{apis,oidcAuthApiRef}from'./apis';import{configApiRef,useApi}from'@backstage/core-plugin-api';constapp=createApp({// Other stuff...
components:{SignInPage: props=>(<SignInPage{...props}autoproviders={useApi(configApiRef).getString('auth.environment')==='development'?['guest']:[{id:'sso-auth-provider',title:'Enterprise SSO',message:'Sign in with Enterprise SSO',apiRef: oidcAuthApiRef}]}/>)}// Other stuff...
})
With the above configuration, authentication will occur as a guest in development mode and via SSO in production mode. For more information, you can check the official documentation
Congratulations, your Backstage application now supports OIDC login. Also take a look at the Keycloak integration for automatique import of user and groups into Backstage.