// file: ~/server/api/auth/[...].ts /* eslint-disable @typescript-eslint/ban-ts-comment */ import { NuxtAuthHandler } from '#auth' import CredentialsProvider from 'next-auth/providers/credentials'; import GithubProvider from 'next-auth/providers/github' import GoogleProvider from 'next-auth/providers/google'; export default NuxtAuthHandler({ // @ts-ignore secret: useRuntimeConfig().authSecret, providers: [ // @ts-expect-error GithubProvider.default({ clientId: useRuntimeConfig().githubClientId, clientSecret: useRuntimeConfig().githubClientSecret }), // @ts-expect-error GoogleProvider.default({ clientId: useRuntimeConfig().googleClientId, clientSecret: useRuntimeConfig().googleClientSecret }), // @ts-expect-error CredentialsProvider.default({ name: 'credentials', credentials: { email: { label: 'email', type: 'email' }, password: { type: 'password', label: 'password' } }, async authorize(credentials: { email: string; password: string } | undefined) { if (!credentials) return null; const config = useRuntimeConfig(); const apiUrl = config.public.BASE_API_URL || 'http://127.0.0.1:8000'; try { const tokenResponse = await fetch(`${apiUrl}/api/v1/auth/jwt/create/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: credentials.email, password: credentials.password }) }); if (!tokenResponse.ok) { return null; } const tokenData = await tokenResponse.json(); const { access, refresh } = tokenData; const userResponse = await fetch(`${apiUrl}/api/v1/auth/users/me/`, { headers: { 'Authorization': `Bearer ${access}` } }); if (!userResponse.ok) { return null; } const userData = await userResponse.json(); // Return a user object with tokens and user data return { ...userData, accessToken: access, refreshToken: refresh }; } catch (error) { console.error('Authorize error:', error); return null; } } }) ], callbacks: { // @ts-ignore jwt: async ({ token, user, account }) => { // The `user` object is from the `authorize` callback. if (user) { // @ts-ignore token.id = user.id; // @ts-ignore token.email = user.email; // @ts-ignore token.name = user.name; // @ts-ignore token.role = user.role; // @ts-ignore token.image = user.image; // @ts-ignore token.is_active = user.is_active; // Persist the tokens in the JWT // @ts-ignore token.accessToken = user.accessToken; // @ts-ignore token.refreshToken = user.refreshToken; } // Social login: exchange provider access_token for backend JWT tokens // This runs only on initial sign-in where `account` is present. if ( account && (account.provider === 'google' || account.provider === 'github') && // @ts-ignore account.access_token ) { try { const config = useRuntimeConfig(); const apiUrl = config.public.BASE_API_URL || 'http://127.0.0.1:8000'; const endpoint = account.provider === 'google' ? `${apiUrl}/api/v1/auth/social/google-oauth2/` : `${apiUrl}/api/v1/auth/social/github/`; // @ts-ignore const accessToken = account.access_token; const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ access_token: accessToken }), }); if (response.ok) { const data = await response.json(); // Expected shape (per docs): { access, refresh, user } // Persist backend JWTs on token so client can call protected APIs. // @ts-ignore token.accessToken = data.access; // @ts-ignore token.refreshToken = data.refresh; if (data.user) { // @ts-ignore token.id = data.user.id ?? token.id; // @ts-ignore token.email = data.user.email ?? token.email; // @ts-ignore token.name = (data.user.name ?? [data.user.first_name, data.user.last_name].filter(Boolean).join(' ')) || token.name; // @ts-ignore token.image = data.user.image ?? token.image; // @ts-ignore token.role = data.user.role ?? token.role; // @ts-ignore token.is_active = data.user.is_active ?? token.is_active; } } else { const text = await response.text().catch(() => ''); console.error('Social token exchange failed:', response.status, text); } } catch (e) { console.error('Social token exchange error:', e); } } return token; }, // @ts-ignore session: async ({ session, token }) => { if (token && session.user) { // @ts-ignore session.user.id = token.id; // @ts-ignore session.user.name = token.name; // @ts-ignore session.user.role = token.role; // @ts-ignore session.user.email = token.email; // @ts-ignore session.user.image = token.image; // @ts-ignore session.user.is_active = token.is_active; } // Expose backend JWTs to the client session (optional but useful) // @ts-ignore session.accessToken = token.accessToken; // @ts-ignore session.refreshToken = token.refreshToken; return session; }, }, // Disable verbose NextAuth logs to avoid DEBUG_ENABLED warning // @ts-ignore debug: false, pages: { signIn: '/auth/login' }, session: { strategy: 'jwt' } })