first commit
This commit is contained in:
219
app/api/auth/[...nextauth]/route.ts
Normal file
219
app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
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<string, string> = {
|
||||
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 };
|
||||
Reference in New Issue
Block a user