import type { NextAuthOptions } from 'next-auth' import type { JWT } from 'next-auth/jwt' import CredentialsProvider from 'next-auth/providers/credentials' import GitHubProvider from 'next-auth/providers/github' import GoogleProvider from 'next-auth/providers/google' import { fetchRefreshedBackendJwt, getJwtExpMs, shouldRefreshBackendToken, } from '@/lib/backend-jwt-refresh' const API_BASE = process.env.API_BASE_URL ?? 'http://localhost:8080' type AuthUser = { id: string email: string username: string accessToken: string refreshToken: string accessTokenExpires: number } async function refreshAccessToken(token: JWT): Promise { const next = await fetchRefreshedBackendJwt(token) if (!next) { return { ...token, error: 'RefreshAccessTokenError', } } return next } export const authOptions: NextAuthOptions = { session: { strategy: 'jwt', /** NextAuth oturum çerezi ömrü (saniye) — backend refresh ile uyumlu uzun süre */ maxAge: 60 * 60 * 24 * 7, }, secret: process.env.NEXTAUTH_SECRET ?? process.env.AUTH_SECRET, providers: [ ...(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET ? [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ] : []), ...(process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET ? [ GitHubProvider({ clientId: process.env.GITHUB_CLIENT_ID, clientSecret: process.env.GITHUB_CLIENT_SECRET, }), ] : []), CredentialsProvider({ name: 'Credentials', credentials: { email: { label: 'Email', type: 'email' }, password: { label: 'Password', type: 'password' }, }, async authorize(credentials) { const email = credentials?.email const password = credentials?.password if (!email || !password) return null const res = await fetch(`${API_BASE}/api/v1/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }) if (!res.ok) return null const data = (await res.json()) as { access: string; refresh: string } const accessToken = data.access const refreshToken = data.refresh return { id: email, email, username: email, accessToken, refreshToken, accessTokenExpires: getJwtExpMs(accessToken), } satisfies AuthUser }, }), ], callbacks: { async jwt({ token, user }) { if (user) { const authUser = user as AuthUser // OAuth login akışında backend access/refresh token'ı yoksa refresh denemeyelim. if (!authUser.accessToken || !authUser.refreshToken) { return { ...token, user: { id: authUser.id, email: authUser.email, username: authUser.username ?? authUser.email, }, } } return { ...token, accessToken: authUser.accessToken, refreshToken: authUser.refreshToken, accessTokenExpires: authUser.accessTokenExpires, user: { id: authUser.id, email: authUser.email, username: authUser.username, }, } } if (token.error === 'RefreshAccessTokenError') { return token } if (!shouldRefreshBackendToken(token)) { return token } return refreshAccessToken(token) }, async session({ session, token }) { session.user = { ...(session.user ?? {}), ...(token.user ?? {}), } session.accessToken = token.accessToken session.refreshToken = token.refreshToken session.error = token.error return session }, }, pages: { signIn: '/auth/login', }, }