import { NuxtAuthHandler } from '#auth' import ZitadelProvider from '@auth/core/providers/zitadel' import { jwtDecode } from 'jwt-decode' const config = useRuntimeConfig() export default NuxtAuthHandler({ secret: config.authSecret, providers: [ ZitadelProvider({ clientId: config.zitadelClientId, issuer: config.zitadelDomain, pkce: true, authorization: { params: { scope: `openid email profile offline_access urn:zitadel:iam:org:project:${config.zitadelProjectId}:aud urn:zitadel:iam:org:project:${config.zitadelProjectId}:roles` } } }) ], 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 } 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.accessToken = token.accessToken as string | undefined // Decode idToken and extract org roles claim if (token.idToken) { try { const decoded = jwtDecode(token.idToken) const roles = decoded[`urn:zitadel:iam:org:project:${config.zitadelProjectId}:roles`] user.roles = roles } catch (error) { console.error('Failed to decode idToken:', error) } } } return session }, async redirect({ url, baseUrl }) { if (url === '/login') return '/login' return url.startsWith(baseUrl) ? url : baseUrl } } })