Search code examples
reactjsnext.jskeycloak

How can I use Keycloak in Next.js?


I'm trying to authenticate in Keycloak in Next.js using @react-keycloak/nextjs but once I pass the login it keeps sending me back to the Keycloak server and returning to the main page until it gives me an error because my token key is expired. This is my _app.js:

import { ApolloProvider } from '@apollo/react-hooks'
import CssBaseline from '@material-ui/core/CssBaseline'
import { ThemeProvider } from '@material-ui/core/styles'
import { Persistors, SSRKeycloakProvider } from '@react-keycloak/nextjs'
import Layout from 'components/layout/Layout'
import { useApollo } from 'lib/apolloClient'
import KeycloakLoading from 'components/KeycloakLoading'
import {
  keycloakCfg,
  keycloakProviderInitConfig,
  onKeycloakLogout,
  onKeycloakTokens,
} from 'lib/keycloak'
import Head from 'next/head'
import PropTypes from 'prop-types'
import React from 'react'
import theme from 'styles/theme'
import 'leaflet/dist/leaflet.css'
import 'react-leaflet-markercluster/dist/styles.min.css'
import 'styles/styles.css'
import 'styles/animations.css'
import '../styles/globals.css'

// export function reportWebVitals(metric) {
//   // These metrics can be sent to any analytics service
//   console.log(metric)
// }

export default function MyApp(props) {
  const { Component, pageProps, cookies } = props

  const apolloClient = useApollo(pageProps.initialApolloState)

  React.useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector('#jss-server-side')
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles)
    }
  }, [])

  return (
    <React.Fragment>
      <Head>
        <title>My page</title>
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width"
        />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <SSRKeycloakProvider
          keycloakConfig={keycloakCfg}
          persistor={Persistors.Cookies(cookies)}
          initConfig={keycloakProviderInitConfig}
          onTokens={onKeycloakTokens}
          onAuthLogout={onKeycloakLogout}
          LoadingComponent={
            <React.Fragment>
              <KeycloakLoading />
            </React.Fragment>
          }
        >
          <ApolloProvider client={apolloClient}>
            <Layout>
              <Component {...pageProps} />
            </Layout>
          </ApolloProvider>
        </SSRKeycloakProvider>
      </ThemeProvider>
    </React.Fragment>
  )
}

MyApp.propTypes = {
  Component: PropTypes.elementType.isRequired,
  pageProps: PropTypes.object.isRequired,
  cookies: PropTypes.any,
}

And this is my Keycloak configuration

export const keycloakCfg = {
  realm: APP_CONSTANTS.KEYCLOAK_REALM,
  url: `${APP_CONSTANTS.KEYCLOAK_HOST}/auth`,
  clientId: APP_CONSTANTS.KEYCLOAK_CLIENT_ID,
}
export const keycloakProviderInitConfig = {
  onLoad: 'login-required',
}

If anyone could point out what is wrong or alternatively tell me another way to use Keycloak in next.


Solution

  • React-keycloak/nextjs is deprecated in favor of react-keycloak/ssr. I followed the examples here: https://www.npmjs.com/package/@react-keycloak/ssr and was able to fully authenticate without issue.

    I'm not sure what is causing your looping issues but it doesn't look like you are using the required cookie parser or passing them into the props via getInitialProps so that may be a good place to start.