Implementing Keycloak on NextJS 13.4 using NextAuth

farisdurrani

Faris Durrani

Posted on July 16, 2023

Implementing Keycloak on NextJS 13.4 using NextAuth

Keycloak logo
Image source

Keycloak is an open-source identity and access management (IAM) solution developed by Red Hat, providing support for SSO as well as protocols such as OpenID Connect, OAuth 2.0, and SAML 2.0. In short, you can use Keycloak as an identity login management tool for your application.

This guide informs you how to install Keycloak on your React NextJS 13.4 application (through the new App Router app/) using NextAuth.

1. Create your NextJS application

Create your NextJS application. Let's call it my-app.

npx create-next-app@latest
Enter fullscreen mode Exit fullscreen mode

Creating your NextJS app using create-next-app

In this tutorial, we are using "next": "13.4.10".

2. Install next-auth

npm i next-auth
Enter fullscreen mode Exit fullscreen mode

NPM installing next-auth

In this tutorial, we are using "next-auth": "^4.22.1".

3. Get your Keycloak credentials

You'll need a Keycloak client which your app will interact with for the authentication process. If you do not have a Keycloak client yet, please see the Keycloak Getting Started guide.

On your deployed Keycloak application, create a new client by clicking on Clients > Create client.

Creating a client on Keycloak

Make sure to enable Client authentication.

Enabling client authentication

Scroll down to add your redirect URL of http://localhost:3000/* and click Save.

Adding redirect URL

Copy your Client secret.

Copying client secret

4. Create your route.ts file

In the new file in the new directory my-app/app/api/auth/[...nextauth]/route.ts, put the following code:

// route.ts
import NextAuth, { NextAuthOptions } from "next-auth";
import { Provider } from "next-auth/providers";
import KeycloakProvider from "next-auth/providers/keycloak";

const KEYCLOAK_CLIENT_ID = "my-app-001";
const KEYCLOAK_CLIENT_SECRET = "uq1DYKs2YGPMGo7B7v6pYs5AlD8YeDVs";
const KEYCLOAK_URL = "http://localhost:8080/auth";
const KEYCLOAK_REALM = "admin";

const KEYCLOAK_ISSUER = `${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}`;

const keycloakConfig = {
  clientId: KEYCLOAK_CLIENT_ID,
  clientSecret: KEYCLOAK_CLIENT_SECRET,
  issuer: KEYCLOAK_ISSUER,
} as const;

const providers: Provider[] = [
  // Configure Keycloak as the authentication provider
  KeycloakProvider(keycloakConfig),
];

const authOptions: NextAuthOptions = { providers };

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };
Enter fullscreen mode Exit fullscreen mode

Note to change the:

  • KEYCLOAK_CLIENT_ID to your client ID
  • KEYCLOAK_CLIENT_SECRET to your copied password
  • KEYCLOAK_URL to your Keycloak deployed URL. It may or may not need the /auth at the end depending on the Keycloak version you're using
  • KEYCLOAK_REALM to your Keycloak realm where you created the client

5. Add the SessionProvider

In a new file my-app/src/app/providers.tsx, copy this in:

"use client";
import React from "react";
import { SessionProvider } from "next-auth/react";

const Providers = ({ children }: { children: React.ReactNode }) => {
  return (
    <>
      <SessionProvider>{children}</SessionProvider>
    </>
  );
};

export default Providers;
Enter fullscreen mode Exit fullscreen mode

Note that "use client" needs to be present at the beginning of the file so this component can render on the client side and use React's client-only functions.

6. Update the layout file

In present file my-app/src/app/layout.tsx, surround the HTML body element with the created Providers component:

import "./globals.css";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import Providers from "./providers";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <Providers>
        <body className={inter.className}>{children}</body>
      </Providers>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

7. Add the .env file

Create a new file my-app/.env with the following. You can learn more about the possible options at the NextAuth Getting Started page

# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=supersecret
Enter fullscreen mode Exit fullscreen mode

8. Add a required login session

In present page my-app/src/app/page.tsx (which is the default page that spins up at http://localhost:3000/), rewrite the default content with this. This will require login to view the page:

"use client";
import { useSession } from "next-auth/react";

export default function Home() {
  const { data: session } = useSession({ required: true });

  return <main>You are now authenticated!</main>;
}
Enter fullscreen mode Exit fullscreen mode

You can optionally console log session here to view the logged-in user's details, e.g., account ID (sub), name, and email.

In the end, we have this folder structure (including the optional middleware.ts file explained in the Bonus section):

Folder structure of project

9. Verify

Start the NextJS app using

npm run dev
Enter fullscreen mode Exit fullscreen mode

Go to http://localhost:3000/ where the app is deployed and see that authentication is required through Keycloak.

localhost:3000 where app is deployed, showing NextAuth login screen

Keycloak login screen

Login success page

Bonus: Enabling global sign-in requirement on NextAuth

To enable sign-in requirement for all pages, simply add a new file my-app/src/middleware.tsx

export { default } from "next-auth/middleware";

export const config = {
  matcher: ["/:path*"],
};
Enter fullscreen mode Exit fullscreen mode

Safe harbor statement
The information provided on this channel/article/story is solely intended for informational purposes and cannot be used as a part of any contractual agreement. The content does not guarantee the delivery of any material, code, or functionality, and should not be the sole basis for making purchasing decisions. The postings on this site are my own and do not necessarily reflect the views or work of Oracle or Mythics, LLC.

This work is licensed under a Creative Commons Attribution 4.0 International License.

💖 💪 🙅 🚩
farisdurrani
Faris Durrani

Posted on July 16, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related