import NextAuth, { NextAuthOptions } from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import GithubProvider from "next-auth/providers/github"; import GoogleProvider from "next-auth/providers/google"; import { JWT } from "next-auth/jwt"; const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000/api/v1"; // Django REST API - Token Refresh async function refreshAccessToken(token: JWT) { try { const response = await fetch( `${API_BASE_URL}/auth/jwt/refresh/`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ refresh: token.refreshToken, }), } ); const data = await response.json(); if (!response.ok) { throw data; } return { ...token, accessToken: data.access, refreshToken: data.refresh ?? token.refreshToken, // Django JWT access token: 60 dakika (3600000 ms) accessTokenExpiry: Date.now() + 3600000, }; } catch (error) { console.error("Error refreshing access token:", error); return { ...token, error: "RefreshAccessTokenError", }; } } // Django REST API - Social Auth Handler async function handleSocialAuth(provider: string, accessToken: string) { const response = await fetch( `${API_BASE_URL}/auth/social/${provider}/`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ access_token: accessToken, }), } ); if (!response.ok) { const error = await response.json(); throw new Error(error.error || "Social authentication failed"); } return await response.json(); } export const authOptions: NextAuthOptions = { providers: [ GithubProvider({ clientId: process.env.GITHUB_ID || "", clientSecret: process.env.GITHUB_SECRET || "", }), GoogleProvider({ clientId: process.env.GOOGLE_ID || "", clientSecret: process.env.GOOGLE_SECRET || "", }), CredentialsProvider({ name: "Django REST API", credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" }, }, async authorize(credentials) { if (!credentials?.email || !credentials?.password) { return null; } try { // Django REST API - Login const response = await fetch( `${API_BASE_URL}/auth/jwt/create/`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email: credentials.email, password: credentials.password, }), } ); if (!response.ok) { return null; } const data = await response.json(); if (data?.access && data?.refresh) { // Get user profile const userResponse = await fetch( `${API_BASE_URL}/auth/users/me/`, { headers: { Authorization: `Bearer ${data.access}`, }, } ); const userData = await userResponse.json(); return { id: userData.id?.toString() || credentials.email, email: userData.email, name: `${userData.first_name || ""} ${userData.last_name || ""}`.trim(), accessToken: data.access, refreshToken: data.refresh, accessTokenExpiry: Date.now() + 3600000, // 60 dakika }; } return null; } catch (error) { console.error("Authentication error:", error); return null; } }, }), ], callbacks: { async jwt({ token, user, account }) { // İlk login - Email/Password (Credentials Provider) if (user && account?.provider === "credentials") { token.accessToken = user.accessToken; token.refreshToken = user.refreshToken; token.accessTokenExpiry = user.accessTokenExpiry; return token; } // İlk login - Social Auth (Google/GitHub) if (account && (account.provider === "google" || account.provider === "github")) { try { const providerMap: Record = { google: "google-oauth2", github: "github", }; const djangoProvider = providerMap[account.provider]; const socialData = await handleSocialAuth( djangoProvider, account.access_token! ); token.accessToken = socialData.access; token.refreshToken = socialData.refresh; token.accessTokenExpiry = Date.now() + 3600000; token.email = socialData.user.email; token.name = `${socialData.user.first_name || ""} ${socialData.user.last_name || ""}`.trim(); return token; } catch (error) { console.error("Social auth error:", error); token.error = "SocialAuthError"; return token; } } // Token hala geçerliyse mevcut tokeni döndür if (token.accessTokenExpiry && Date.now() < (token.accessTokenExpiry as number)) { return token; } // Token süresi dolmuşsa refresh et return refreshAccessToken(token); }, async session({ session, token }) { session.accessToken = token.accessToken as string; session.refreshToken = token.refreshToken as string; session.error = token.error as string | undefined; if (token.email) { session.user = { ...session.user, email: token.email as string, name: token.name as string, }; } return session; }, }, pages: { signIn: "/auth/login", error: "/auth/error", }, session: { strategy: "jwt", maxAge: 7 * 24 * 60 * 60, // 7 gün (refresh token süresi) }, secret: process.env.NEXTAUTH_SECRET, }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };