Skip to content

Instantly share code, notes, and snippets.

@mingyuchoo
Created December 23, 2023 11:20
Show Gist options
  • Save mingyuchoo/aa2336eea7a849f4d6169fb393cdbb03 to your computer and use it in GitHub Desktop.
Save mingyuchoo/aa2336eea7a849f4d6169fb393cdbb03 to your computer and use it in GitHub Desktop.
How to connect KeyCloak and Backstage locally

How to connect KeyCloak and Backstage locally

Prerequsites

Prepare KeyCloak server locally

  • Before useing Docker Compose file, install Docker engine on your machine.
  • Please use this here file.
  • Connect to http://127.0.0.1:8080 in your web browser. Due to some problems, localhost was not recognized when running Docker on Mac, so I changed it to 127.0.0.1.

Prepare Backstage locally

  • Before creating Backstage project, install node and yarn first.
  • Create Backstage project.
$ npx @backstage/create-app
Need to install the following packages:
@backstage/create-app@0.5.8
Ok to proceed? (y) y
? Enter a name for the app [required] dev-backstage
$ cd dev-backstage
$ yarn dev
  • Connect to http://localhost:3000 in your web browser.

Set up KeyCloak

Create application(a.k.a client) for Backstage

  • Login your KeyCloak as admin

Ok! Done

Set up Backstage

You should modify at least 4 files to connect KeyCloak and Backstage

Backstage configurations file

  • Please refer here
  • Edit ${PROJECT_HOME}/app-config.yaml file as show below.
# ...
auth:
  # see https://backstage.io/docs/auth/ to learn about auth providers
  environment: development
  session:
    secret: MY-SECRET-KEY
  providers:
    oidc:
      development:
        metadataUrl: http://127.0.0.1:8080/realms/master/.well-known/openid-configuration 
        clientId: ${KEYCLOAK_CLIENT_ID}
        clientSecret: ${KEYCLOAK_CLIENT_SECRET}
        
# ...

Backstage server file

  • Please refer here
  • Edit ${PROJECT_HOME}/packages/backend/src/plugins/auth.ts file as show below.
// ...

import { stringifyEntityRef, DEFAULT_NAMESPACE } from '@backstage/catalog-model';

export default async function createPlugin(
  env: PluginEnvironment,
): Promise<Router> {
  return await createRouter({
    logger: env.logger,
    config: env.config,
    database: env.database,
    discovery: env.discovery,
    tokenManager: env.tokenManager,
    providerFactories: {
      ...defaultAuthProviderFactories,
      oidc: providers.oidc.create({
        signIn: {
          resolver(info, ctx) {
            const userRef = stringifyEntityRef({
              kind: 'User',
              name: info.result.userinfo.sub,
              namespace: DEFAULT_NAMESPACE,
            });
            return ctx.issueToken({
              claims: {
                sub: userRef,
                ent: [userRef],
              },
            });
          },
        },
      }),
// ...

Backstage client file

  • Please refer here
  • Edit ${PROJECT_HOME}/packages/app/src/apis.tsx file as show below.
// ...
import { OAuth2 } from '@backstage/core-app-api';

export const localOIDCAuthApiRef: ApiRef<
  OAuthApi & OpenIdConnectApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
> = createApiRef({
  id: 'internal.auth.oidc',
});

export const apis: AnyApiFactory[] = [
  createApiFactory({
    api: localOIDCAuthApiRef,
    deps: {
      discoveryApi: discoveryApiRef,
      oauthRequestApi: oauthRequestApiRef,
      configApi: configApiRef,
    },
    factory: ({ discoveryApi, oauthRequestApi, configApi }) =>
      OAuth2.create({
        discoveryApi,
        oauthRequestApi,
        provider: {
          id: 'oidc',
          title: 'My OIDC provider',
          icon: () => null,
        },
        environment: configApi.getOptionalString('auth.environment'),
        defaultScopes: ['openid', 'profile', 'email'],
        popupOptions: {
          size: {
            width: 1000,
            height: 1000,
          },
        },
      }),
  }),
// ...
  • Edit ${PROJECT_HOME}/packages/app/src/App.tsx file as show below.
// ...
import { apis, localOIDCAuthApiRef } from './apis';
// ...
const app = createApp({
  components: {
    SignInPage: props => (
      <SignInPage
        {...props}
        providers={[
          {
            id: 'oidc',
            title: 'KeyCloak',
            message: 'Sign in using KeyCloak',
            apiRef: localOIDCAuthApiRef,
          },
          // ...
        ]}
      />
    ),
  },
// ...

Check connectivity

  • When you connect to http://localhost:3000 in your web browser, you can see KeyCloak 'SIGN IN' button.
  • When you click the 'SIGN IN' button, you can see popup window for login.
  • When you type in you credential (id, password) you can login to your local Backstage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment