Keycloak and NextJS: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
 
(4 intermediate revisions by the same user not shown)
Line 5: Line 5:
Awful way to document but here goes<br>
Awful way to document but here goes<br>
[[File:Keycloak setup1.png |600px]]
[[File:Keycloak setup1.png |600px]]
==Create a Client==
==Add Capabilities==
Awful way to document but here goes<br>
Set the flow<br>
[[File:Keycloak setup2.png |600px]]
[[File:Keycloak setup2.png |600px]]
==Add Redirect==
==Add Redirect==
Line 14: Line 14:
Next this <br>
Next this <br>
[[File:Keycloak setup4.png |600px]]
[[File:Keycloak setup4.png |600px]]
==Create User==
Create the user<br>
[[File:Keycloak setup5.png |600px]]
==Set The Password==
Set The Password<br>
[[File:Keycloak setup6.png |600px]]
=NextJS Bit=
==Setup Auth==
Make the nextauth bits
<syntaxhighlight lang="bash">
mkdir -p "src/app/api/auth/[...nextauth]" && touch "src/app/api/auth/[...nextauth]/route.ts"
</syntaxhighlight>
Implement the root.ts
<syntaxhighlight lang="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
</syntaxhighlight>
Fix up ProcessEnv
<syntaxhighlight lang="bash">
mkdir types && touch types/node-env.d.ts
</syntaxhighlight>
And
<syntaxhighlight lang="ts">
// types/node-env.d.ts
declare namespace NodeJS {
  export interface ProcessEnv {
    KEYCLOAK_CLIENT_ID: string
    KEYCLOAK_CLIENT_SECRET: string
    KEYCLOAK_ISSUER: string
  }
}
</syntaxhighlight>
And
<syntaxhighlight lang="bash">
touch .env.local
</syntaxhighlight>
And add
<syntaxhighlight lang="bash">
KEYCLOAK_CLIENT_ID="nextjs"
KEYCLOAK_CLIENT_SECRET="<client_secret>"
KEYCLOAK_ISSUER="http://localhost:8080/realms/myrealm"
</syntaxhighlight>
==Login Page==
Home Page
<syntaxhighlight lang="ts">
// 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>
  )
}
</syntaxhighlight>
Login Component
<syntaxhighlight lang="ts">
// 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>
}
</syntaxhighlight>
Logout Component
<syntaxhighlight lang="ts">
// src/components/Logout.tsx
"use client"
import { signOut } from "next-auth/react";
export default function Logout() {
  return <button onClick={() => signOut()}>
    Signout of keycloak
  </button>
}
</syntaxhighlight>

Latest revision as of 04:55, 28 April 2025

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>
}