2024-01-04 03:56:24 -05:00
import NextAuth , { DefaultSession } from "next-auth"
import { JWT } from "@auth/core/jwt"
2024-01-02 02:26:20 -05:00
import { PrismaAdapter } from "@auth/prisma-adapter"
import { db } from "@/lib/db"
import authConfig from "@/auth.config"
2024-01-04 03:56:24 -05:00
import { getUserById } from "./data/user"
2024-01-04 16:57:32 -05:00
import { User , UserRole } from "@prisma/client"
import { getImpersonationById } from "./data/impersonation"
2024-01-04 03:56:24 -05:00
declare module "@auth/core/types" {
/ * *
* Returned by ` useSession ` , ` getSession ` and received as a prop on the ` SessionProvider ` React Context
* /
interface Session {
user : {
2024-01-04 16:57:32 -05:00
role : UserRole | null
impersonation : User | null
2024-01-04 03:56:24 -05:00
// By default, TypeScript merges new interface properties and overwrite existing ones. In this case, the default session user properties will be overwritten, with the new one defined above. To keep the default session user properties, you need to add them back into the newly declared interface
} & DefaultSession [ "user" ] // To keep the default types
}
}
declare module "@auth/core/jwt" {
/** Returned by the `jwt` callback and `auth`, when using JWT sessions */
interface JWT {
2024-01-04 16:57:32 -05:00
role : UserRole | null
impersonation : User | null
2024-01-04 03:56:24 -05:00
}
}
2024-01-02 02:26:20 -05:00
export const {
handlers : { GET , POST } ,
auth ,
signIn ,
signOut ,
} = NextAuth ( {
events : {
async linkAccount ( { user } ) {
await db . user . update ( {
where : { id : user.id } ,
data : { emailVerified : new Date ( ) }
} )
}
} ,
callbacks : {
async session ( { session , user , token } ) {
if ( token . sub && session . user ) {
session . user . id = token . sub
}
2024-01-04 03:56:24 -05:00
if ( token . role && session . user ) {
session . user . role = token . role
2024-01-04 16:57:32 -05:00
} else {
session . user . role = null
}
if ( token . impersonation && session . user ) {
session . user . impersonation = token . impersonation
} else {
token . impersonation = null
2024-01-04 03:56:24 -05:00
}
2024-01-02 02:26:20 -05:00
return session
} ,
2024-01-04 16:57:32 -05:00
async jwt ( { token , user , account , profile } ) {
2024-01-04 03:56:24 -05:00
if ( ! token . sub ) return token
const existingUser = await getUserById ( token . sub )
if ( ! existingUser ) return token
2024-01-04 16:57:32 -05:00
// Update Role
2024-01-04 03:56:24 -05:00
token . role = existingUser . role
2024-01-04 16:57:32 -05:00
// Update Impersonation
const impersonation = await getImpersonationById ( existingUser . id )
if ( token . role == "ADMIN" && impersonation && impersonation . targetId != existingUser . id ) {
const impersonationUser = await getUserById ( impersonation . targetId )
if ( impersonation ) {
token . impersonation = impersonationUser
} else {
token . impersonation = null
}
} else if ( impersonation && impersonation . targetId == existingUser . id ) {
await db . impersonation . delete ( {
where : {
sourceId : existingUser.id
}
} )
token . impersonation = null
} else {
token . impersonation = null
}
2024-01-02 02:26:20 -05:00
return token
}
} ,
adapter : PrismaAdapter ( db ) ,
session : { strategy : "jwt" } ,
. . . authConfig ,
} )