Integrating Keycloak in React & Next.js applications

2022-01-09

Keycloak is an Open Source Identity and Access Management solution for modern Applications and Services.

In this post, we will see how to integrate Keycloak into a React & Next.js Application.

Integrating in React application

Let's go ahead and install the keycloak javascript adapter and the react library for Keycloak.

npm install --save keycloak-js

npm install --save @react-keycloak/web

or

yarn add keycloak-js

yarn add @react-keycloak/web

Configure your Keycloak instance as needed by creating a keycloak.js file in your project's src folder with the following content:

import Keycloak from 'keycloak-js'
const keycloakConfig = {
  url: 'http://localhost:8080/auth',
  realm: 'Demo-Realm',
  clientId: 'web-app',
}
const keycloak = new Keycloak(keycloakConfig)
export default keycloak

💡 Hint

You can intialize Keyclock through a ./keycloak.json file by leaving the constructor value empty.

const keycloak = new Keycloak()

Then Wrap your App inside KeycloakProvider and pass the keycloak instance as prop

import React from 'react'
import { KeycloakProvider } from '@react-keycloak/web'
import keycloak from './keycloak'
// If you are using other providers (such as react-redux) it is recommended to place them inside KeycloakProvider.
const App = () => {
  return (
    <KeycloakProvider keycloak={keycloak}>
      <div className="App">{/* place your router or application here */}</div>
    </KeycloakProvider>
  )
}

Integrating in SSR rendered Next.js application

Let's go ahead and install the keycloak javascript adapter and the react library for Keycloak.

npm install --save keycloak-js

npm install --save @react-keycloak/ssr

or

yarn add keycloak-js

yarn add @react-keycloak/ssr

Create the _app.tsx file under pages folder and wrap your App inside SSRKeycloakProvider component and pass keycloakConfig and a TokenPersistor.

Note: @react-keycloak/ssr provides a default TokenPersistor which works with cookies (exported as ServerPersistors.SSRCookies).

The following examples will be based on that.

import cookie from 'cookie'
import * as React from 'react'
import type { IncomingMessage } from 'http'
import type { AppProps, AppContext } from 'next/app'

import { SSRKeycloakProvider, SSRCookies } from '@react-keycloak/ssr'

const keycloakCfg = {
  realm: '',
  url: '',
  clientId: '',
}

interface InitialProps {
  cookies: unknown
}

function MyApp({ Component, pageProps, cookies }: AppProps & InitialProps) {
  return (
    <SSRKeycloakProvider
      keycloakConfig={keycloakCfg}
      persistor={SSRCookies(cookies)}
    >
      <Component {...pageProps} />
    </SSRKeycloakProvider>
  )
}

function parseCookies(req: IncomingMessage) {
  return cookie.parse(req.headers.cookie || '')
}

MyApp.getInitialProps = async (context: AppContext) => {
  // Extract cookies from AppContext
  return {
    cookies: context.ctx.req ? parseCookies(context.ctx.req) : {},
  }
}

export default MyApp

Integrating in Static Generated Next.js application

Let's go ahead and install the keycloak javascript adapter and the react library for Keycloak.

npm install --save keycloak-js

npm install --save @react-keycloak/web

or

yarn add keycloak-js

yarn add @react-keycloak/web

Create the _app.tsx file under pages folder and wrap your App inside KeycloakProvider component and pass keycloakConfig and a TokenPersistor.

Note: @react-keycloak/ssr provides a default TokenPersistor which works with cookies (exported as ServerPersistors.SSRCookies).

The following examples will be based on that.

import dynamic from 'next/dynamic'
import { ReactKeycloakProvider } from '@react-keycloak/web'
import LoadingScreen from 'components/LoadingScreen'

const App = ({ Component, pageProps }: AppProps): JSX.Element => {
  const Keycloak = typeof window !== 'undefined' ? require('keycloak-js') : null
  const keycloak = Keycloak() // will load instance configuration from keycloak.json

  const keycloakInitOptions = { onLoad: 'login-required' }
  return (
    <ReactKeycloakProvider
      authClient={keycloak}
      initOptions={keycloakInitOptions}
      LoadingComponent={<LoadingScreen />}
    >
      <Component {...pageProps} />
    </ReactKeycloakProvider>
  )
}

// we have disabled SSR rendering here
export default dynamic(() => Promise.resolve(App), {
  ssr: false,
})

In the above example we have used a LoadingScreen component that will be rendered to the user till the keycloak adapter is initialized.

const keycloakInitOptions = { onLoad: 'login-required' }

This Initialization option makes Keycloak login immediately.

Conclusion

TODO.log