Keycloak and NextJS

From bibbleWiki
Revision as of 04:55, 28 April 2025 by Iwiseman (talk | contribs) (NextJS Bit)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

Only do it once a project so wanted to capture how to this. Thanks to Harsh Bhandari

Keycloak

Create a Client

Awful way to document but here goes

Add Capabilities

Set the flow

Add Redirect

This is for nextauth

Get The Secret

Next this

Create User

Create the user

Set The Password

Set The Password

NextJS Bit

Setup Auth

Make the nextauth bits

mkdir -p "src/app/api/auth/[...nextauth]" && touch "src/app/api/auth/[...nextauth]/route.ts"

Implement the root.ts

// src/app/api/auth/[...nextauth]/route.ts
import { AuthOptions } from "next-auth";
import KeycloakProvider from "next-auth/providers/keycloak"
export const authOptions: AuthOptions = {
  providers: [
    KeycloakProvider({
      clientId: process.env.KEYCLOAK_CLIENT_ID,
      clientSecret: process.env.KEYCLOAK_CLIENT_SECRET,
      issuer: process.env.KEYCLOAK_ISSUER
    })
  ]
}
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST

Fix up ProcessEnv

mkdir types && touch types/node-env.d.ts

And

// types/node-env.d.ts
declare namespace NodeJS {
  export interface ProcessEnv {
    KEYCLOAK_CLIENT_ID: string
    KEYCLOAK_CLIENT_SECRET: string
    KEYCLOAK_ISSUER: string
  }
}

And

touch .env.local

And add

KEYCLOAK_CLIENT_ID="nextjs"
KEYCLOAK_CLIENT_SECRET="<client_secret>"
KEYCLOAK_ISSUER="http://localhost:8080/realms/myrealm"

Login Page

Home Page

// src/app/page.tsx
import { getServerSession } from 'next-auth'
import { authOptions } from './api/auth/[...nextauth]/route'
import Login from '../components/Login'
import Logout from '../components/Logout'
export default async function Home() {
  const session = await getServerSession(authOptions)
  if (session) {
    return <div>
      <div>Your name is {session.user?.name}</div>
      <div><Logout /> </div>
    </div>
  }
  return (
    <div>
      <Login />
    </div>
  )
}

Login Component

// src/components/Login.tsx
"use client"
import { signIn } from "next-auth/react";
export default function Login() {
  return <button onClick={() => signIn("keycloak")}>
    Signin with keycloak
  </button>
}

Logout Component

// src/components/Logout.tsx
"use client"
import { signOut } from "next-auth/react";
export default function Logout() {
  return <button onClick={() => signOut()}>
    Signout of keycloak
  </button>
}