1
0
Fork 0
This repository has been archived on 2025-08-23. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
mareshq-backoffice-v1-monolith/src/server/auth.ts
Vojtech Mares 377e9e9570
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.
2023-09-03 10:50:40 +02:00

126 lines
3.8 KiB
TypeScript

import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { type GetServerSidePropsContext } from "next";
import {
getServerSession,
type NextAuthOptions,
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";
/**
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
* object and keep type safety.
*
* @see https://next-auth.js.org/getting-started/typescript#module-augmentation
*/
declare module "next-auth" {
interface Session extends DefaultSession {
user: {
id: string;
// ...other properties
// role: UserRole;
} & DefaultSession["user"];
}
// interface User {
// // ...other properties
// // role: UserRole;
// }
}
/**
* 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.
*
* @see https://next-auth.js.org/configuration/options
*/
export const authOptions: NextAuthOptions = {
callbacks: {
session: ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id,
email: user.email,
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: [
KeycloakProvider({
clientId: env.KEYCLOAK_CLIENT_ID,
clientSecret: env.KEYCLOAK_CLIENT_SECRET,
issuer: env.KEYCLOAK_ISSUER,
// authorizationUrl: env.KEYCLOAK_ISSUER + "/protocol/openid-connect/auth",
// accessTokenUrl: env.KEYCLOAK_ISSUER + "/protocol/openid-connect/token",
// profileUrl: env.KEYCLOAK_ISSUER + "/protocol/openid-connect/userinfo",
// wellKnown: env.KEYCLOAK_ISSUER + "/.well-known/openid-configuration",
}),
/**
* ...add more providers here.
*
* Most other providers require a bit more work than the Discord provider. For example, the
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
* model. Refer to the NextAuth.js docs for the provider you want to use. Example:
*
* @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<KeycloakProfile>).options!.issuer!
const logOutUrl = new URL(`${issuerUrl}/protocol/openid-connect/logout`)
logOutUrl.searchParams.set("id_token_hint", token.id_token!)
await fetch(logOutUrl);
}
},
}
};
/**
* Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file.
*
* @see https://next-auth.js.org/configuration/nextjs
*/
export const getServerAuthSession = (ctx: {
req: GetServerSidePropsContext["req"];
res: GetServerSidePropsContext["res"];
}) => {
return getServerSession(ctx.req, ctx.res, authOptions);
};