All checks were successful
Build and Publish / build-release (push) Successful in 1m1s
83 lines
2.9 KiB
TypeScript
83 lines
2.9 KiB
TypeScript
import { NuxtAuthHandler } from '#auth'
|
|
import ZitadelProvider from '@auth/core/providers/zitadel'
|
|
|
|
export default NuxtAuthHandler({
|
|
secret: process.env.AUTH_SECRET,
|
|
providers: [
|
|
ZitadelProvider({
|
|
clientId: process.env.ZITADEL_CLIENT_ID,
|
|
issuer: process.env.ZITADEL_DOMAIN,
|
|
authorization: {
|
|
params: {
|
|
scope: `openid email profile offline_access urn:zitadel:iam:org:project:${process.env.ZITADEL_PROJECT_ID}:aud`
|
|
}
|
|
}
|
|
})
|
|
],
|
|
session: {
|
|
strategy: 'jwt',
|
|
maxAge: 30 * 24 * 60 * 60, // 30 days
|
|
},
|
|
callbacks: {
|
|
async jwt({ token, account, user }) {
|
|
if (account?.provider === 'zitadel') {
|
|
token.accessToken = account.access_token
|
|
token.idToken = account.id_token
|
|
token.roles = (user as any)?.roles
|
|
|
|
/* Extract org roles from ID token claims */
|
|
const allOrgRoles: Record<string, Record<string, Record<string, string>>> = {}
|
|
const idTokenClaims = (() => {
|
|
try {
|
|
const parts = (account.id_token || '').split('.')
|
|
if (parts.length === 3) {
|
|
const payload = Buffer.from(parts[1], 'base64url').toString('utf8')
|
|
return JSON.parse(payload) as Record<string, any>
|
|
}
|
|
} catch { /* ignore */ }
|
|
return null
|
|
})()
|
|
if (idTokenClaims) {
|
|
for (const key of Object.keys(idTokenClaims)) {
|
|
if (key.startsWith('urn:zitadel:iam:org:project:') && key.endsWith(':roles')) {
|
|
allOrgRoles[key] = idTokenClaims[key]
|
|
}
|
|
}
|
|
}
|
|
/* Also check userinfo response for org role claims */
|
|
for (const key of Object.keys((user as any) || {})) {
|
|
if (key.startsWith('urn:zitadel:iam:org:project:') && key.endsWith(':roles')) {
|
|
allOrgRoles[key] = (user as any)[key]
|
|
}
|
|
}
|
|
token.allOrgRoles = Object.keys(allOrgRoles).length > 0 ? allOrgRoles : undefined
|
|
}
|
|
if (user?.id) {
|
|
token.sub = user.id
|
|
if (user.name || (user as any).profile?.given_name) {
|
|
token.name = user.name || ((user as any).profile?.given_name || '')
|
|
}
|
|
token.email = user.email || ''
|
|
token.image = user.image || undefined
|
|
}
|
|
return token
|
|
},
|
|
async session({ session, token }) {
|
|
const user = session.user as any
|
|
if (user) {
|
|
user.name = token.name || undefined
|
|
user.email = token.email || undefined
|
|
user.image = token.image || undefined
|
|
user.roles = token.roles as string[] | undefined
|
|
user.accessToken = token.accessToken as string | undefined
|
|
user.allOrgRoles = token.allOrgRoles as Record<string, Record<string, Record<string, string>>> | undefined
|
|
}
|
|
return session
|
|
},
|
|
async redirect({ url, baseUrl }) {
|
|
if (url === '/login') return '/login'
|
|
return url.startsWith(baseUrl) ? url : baseUrl
|
|
}
|
|
}
|
|
})
|