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

173 lines
5.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";
2025-01-11 03:10:04 +00:00
import NextAuth, { User, Profile } from "next-auth";
2024-12-12 07:23:46 +00:00
import { configs } from "../config/configs";
2025-01-11 03:10:04 +00:00
import { extractCurrentlyEntitledTiers, mapTierIdsToRoles } from "./patreon";
2024-12-16 20:39:23 +00:00
import { getTierNameFromTierId } from "./keycloak";
2025-01-11 03:10:04 +00:00
import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers/oauth";
2024-12-12 07:23:46 +00:00
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;
}
}
2025-01-11 03:10:04 +00:00
export interface PatreonProfile extends Record<string, any> {
sub: string
nickname: string
email: string
picture: string
}
export default function Patreon<P extends PatreonProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {
id: "patreon",
name: "Patreon",
type: "oauth",
version: "2.0",
authorization: {
url: "https://www.patreon.com/oauth2/authorize",
params: { scope: "identity" },
},
token: "https://www.patreon.com/api/oauth2/token",
userinfo: "https://www.patreon.com/api/oauth2/v2/identity?fields%5Buser%5D=about,created,email,first_name,full_name,image_url,last_name,thumb_url,url,vanity&include=memberships,memberships.currently_entitled_tiers,memberships.currently_entitled_tiers.benefits",
profile(profile) {
console.log(`profile callback!!!! userinfo as follows`)
// console.log(profile)
const tiers = extractCurrentlyEntitledTiers(profile)
console.log(tiers)
return {
id: profile.data.id,
name: profile.data.attributes.full_name,
email: profile.data.attributes.email,
image: profile.data.attributes.image_url,
currently_entitled_tiers: tiers
}
},
style: { logo: "/patreon.svg", bg: "#e85b46", text: "#fff" },
options,
}
}
2024-12-12 07:23:46 +00:00
export const authOptions: NextAuthOptions = {
2024-12-16 20:39:23 +00:00
session: {
strategy: "jwt"
},
2024-12-12 07:23:46 +00:00
providers: [
2025-01-11 03:10:04 +00:00
Patreon({
clientId: configs.patreonClientId,
clientSecret: configs.patreonClientSecret,
2024-12-12 07:23:46 +00:00
})
],
callbacks: {
2025-01-11 03:10:04 +00:00
// Using the `...rest` parameter to be able to narrow down the type based on `trigger`
jwt({ token, trigger, session, account, profile, user }) {
console.log(`next-auth jwt callback! trigger=${trigger}`)
2024-12-16 20:39:23 +00:00
if (account) {
2025-01-11 03:10:04 +00:00
console.log(`>>>> account was present!`)
console.log(account)
console.log(user)
token.currently_entitled_tiers = user.currently_entitled_tiers
}
if (trigger === 'signIn' && profile) {
console.log('trigger is signIn and profile as follows')
console.log(profile)
token.test = true
2024-12-16 20:39:23 +00:00
return token
2024-12-12 07:23:46 +00:00
}
2025-01-11 03:10:04 +00:00
if (trigger === "update" && session?.name) {
// Note, that `session` can be any arbitrary object, remember to validate it!
token.name = session.name
}
2024-12-12 07:23:46 +00:00
2025-01-11 03:10:04 +00:00
token.test = 'yessir'
return token
},
async session({ session, token, user }) {
console.log('Send properties to the client, like an access_token and user id from a provider.')
console.log(token)
console.log(session)
console.log(user)
2024-12-12 07:23:46 +00:00
session.token = token
2025-01-11 03:10:04 +00:00
if (token?.currently_entitled_tiers) {
session.roles = mapTierIdsToRoles(token.currently_entitled_tiers)
}
2024-12-12 07:23:46 +00:00
return session
}
}
}
2025-01-11 03:10:04 +00:00
export const { handler, signIn, signOut, auth } = NextAuth(authOptions)
2024-12-12 07:23:46 +00:00
// 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
// },