From 377e9e957090147801d28b144d4dfbbf76806337 Mon Sep 17 00:00:00 2001 From: Vojtech Mares Date: Sun, 3 Sep 2023 10:50:40 +0200 Subject: [PATCH] feat(nextauth): properly handle signout When signing out, by default keycloak session is not terminated, this fixes it and sends a request to keycloak instance to terminate the keycloak session. --- src/server/auth.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/server/auth.ts b/src/server/auth.ts index 3328cf6..9c2ce0c 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -6,6 +6,9 @@ import { type DefaultSession, } from "next-auth"; import KeycloakProvider from "next-auth/providers/keycloak"; +import { type KeycloakProfile } from "next-auth/providers/keycloak"; +import { type JWT } from "next-auth/jwt"; +import { type OAuthConfig } from "next-auth/providers"; import { env } from "~/env.mjs"; import { prisma } from "~/server/db"; @@ -30,6 +33,18 @@ declare module "next-auth" { // } } +/** + * Part of the Keycloak fix/workaround, see code bellow for method `signOut`. + * + * @see https://stackoverflow.com/a/75526977 + */ +declare module 'next-auth/jwt' { + interface JWT { + id_token?: string; + provider?: string; + } +} + /** * Options for NextAuth.js used to configure adapters, providers, callbacks, etc. * @@ -46,6 +61,18 @@ export const authOptions: NextAuthOptions = { image: user.image, }, }), + /** + * Part of the Keycloak fix/workaround, see code bellow for method `signOut`. + * + * @see https://stackoverflow.com/a/75526977 + */ + async jwt({ token, account }) { + if (account) { + token.id_token = account.id_token + token.provider = account.provider + } + return token + }, }, adapter: PrismaAdapter(prisma), providers: [ @@ -68,6 +95,22 @@ export const authOptions: NextAuthOptions = { * @see https://next-auth.js.org/providers/github */ ], + events: { + /** + * Fix for Keycloak not destroying the session token on logout, + * we must send an extra request to delete the session. + * + * @see https://stackoverflow.com/a/75526977 + */ + async signOut({ token }: { token: JWT }) { + if (token.provider === "keycloak") { + const issuerUrl = (authOptions.providers.find(p => p.id === "keycloak") as OAuthConfig).options!.issuer! + const logOutUrl = new URL(`${issuerUrl}/protocol/openid-connect/logout`) + logOutUrl.searchParams.set("id_token_hint", token.id_token!) + await fetch(logOutUrl); + } + }, + } }; /**