fp/services/next/app/lib/auth.ts

135 lines
4.0 KiB
TypeScript
Raw Normal View History

2024-12-12 07:23:46 +00:00
import KeycloakProvider, { type KeycloakProfile } from "next-auth/providers/keycloak";
import { NextAuthOptions } from "next-auth";
import { jwtDecode } from "jwt-decode";
import { type JWT } from "next-auth/jwt";
import { User, Profile } from "next-auth";
import { configs } from "../config/configs";
import { getPatreonMemberships, getKeycloakIdpToken, updateKeycloakUserPatreonEntitlements } from "./patreon";
declare module "next-auth" {
interface Session {
user: User;
token: JWT | undefined;
profile: Profile;
}
interface Profile {
realm_access: any;
preferred_username: string;
username_visibility?: "public" | "private";
}
interface Session {
roles: any
}
}
declare module "next-auth/jwt" {
interface JWT {
expires_at: number;
access_token: string;
refresh_token: string;
profile: Profile;
}
}
export const authOptions: NextAuthOptions = {
providers: [
KeycloakProvider({
clientId: configs.keycloakClientId,
clientSecret: configs.keycloakClientSecret,
issuer: configs.keycloakIssuer
})
],
callbacks: {
async jwt({ token, account, profile }) {
// console.log(`jwt() callback. account as follows.`)
// console.log(account)
// console.log(`jwt() callback. token as follows.`)
// console.log(token)
console.log(`jwt() callback. profile as follows.`)
console.log(profile)
if (account) {
const decodedAccountToken = jwtDecode(account.access_token as any) as KeycloakProfile
console.log(`jwt() callback. decodedAccountToken as follows.`)
console.log(decodedAccountToken)
token.client_roles = decodedAccountToken.realm_access.roles
token.scope = decodedAccountToken.scope
token.expires_at = account.expires_at ?? 0;
token.access_token = account.access_token!;
token.refresh_token = account.refresh_token!;
}
if (profile) {
token.profile = profile
}
return token;
},
async session({ session, token, trigger }) {
// console.log(`Token interceptor to add token info to the session to use on the pages. trigger=${trigger}`)
// console.log(JSON.stringify(token, null, 2))
// console.log('session as follows')
// console.log(JSON.stringify(session, null, 2))
const userId = token?.sub
if (!userId) throw new Error('failed to get userId from token.sub');
// side effect which gets user's patreon tiers and adds them to the appropriate keycloak group
await updateKeycloakUserPatreonEntitlements(token)
// session.account = token.account
session.profile = token.profile
session.roles = token.client_roles
session.token = token
return session
}
}
}
// async jwt({ token, account, profile }) {
// try {
// if (account) {
// const decodedToken = jwtDecode(account.access_token as any)
// if (token == null){
// throw new Error("Unable to decode token")
// }
// console.log('decodedToken as follows')
// console.log(JSON.stringify(decodedToken, null, 2))
// // Do something here to add more info, maybe just overwrite profile (thats the one that should have this info)
// profile = decodedToken
// token.account = account
// }
// if (profile) {
// console.log('profile as follows')
// console.log(profile)
// token.profile = profile
// // Then do here the assignation of roles elements to token so session has access
// // This can be modified so uses by client, realm or account BE AWARE OF THAT!
// // Modify the "resource_access['next-auth-AFB']" value to the one your resource/realm/accout
// // json scope roles you need
// // While the info is already on profile, we could make a new key on the json response of session
// const clientRoles = profile.realm_access.roles
// token.client_roles = clientRoles
// }
// } catch (error) {
// console.log(error)
// }
// return token
// },