135 lines
4.0 KiB
TypeScript
135 lines
4.0 KiB
TypeScript
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
|
|
// },
|