Files
next-fiber/lib/auth-api.ts
Beyhan Oğur b2825e1698 first commit
2026-04-26 22:14:08 +03:00

177 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Auth API client for login, register, me, refresh.
* Uses NEXT_PUBLIC_BASE_API_URL on client (defaults to same as BASE_API_URL for server).
*/
const getBaseUrl = () =>
typeof window !== "undefined"
? process.env.NEXT_PUBLIC_BASE_API_URL ?? "http://127.0.0.1:8080"
: process.env.BASE_API_URL ?? process.env.NEXT_PUBLIC_BASE_API_URL ?? "http://127.0.0.1:8080";
const API_PREFIX = "/api/v1/auth";
export interface AuthUser {
id: number;
email: string;
first_name: string;
last_name: string;
username?: string;
is_admin: boolean;
email_verified?: boolean;
}
export interface LoginResponse {
access_token: string;
refresh_token: string;
user: AuthUser;
}
export interface RegisterResponse {
message: string;
user: AuthUser;
}
export interface RefreshResponse {
access_token: string;
refresh_token: string;
}
/** POST /api/v1/auth/login doğrudan backend (token clientta; cookie için loginViaCookie kullanın) */
export async function login(
email: string,
password: string
): Promise<LoginResponse> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/login`, {
method: "POST",
headers: { "Content-Type": "application/json", accept: "application/json" },
body: JSON.stringify({ email, password }),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error((err as { detail?: string }).detail ?? "Giriş başarısız");
}
return res.json();
}
/** Cookie tabanlı giriş tokenlar HTTP-only secure cookiede saklanır */
export async function loginViaCookie(
email: string,
password: string
): Promise<{ user: AuthUser }> {
const res = await fetch("/api/auth/cookie-login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: email.trim(), password }),
credentials: "include",
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
throw new Error((data as { error?: string }).error ?? "Giriş başarısız");
}
return data as { user: AuthUser };
}
/** Cookie tabanlı çıkış */
export async function logoutViaCookie(): Promise<void> {
await fetch("/api/auth/cookie-logout", {
method: "POST",
credentials: "include",
});
}
/** Cookie oturumunu kontrol et (client tarafında oturum bilgisi için) */
export async function getCookieSession(): Promise<{
loggedIn: boolean;
user?: AuthUser;
}> {
const res = await fetch("/api/auth/cookie-session", { credentials: "include" });
const data = await res.json().catch(() => ({ loggedIn: false }));
return data as { loggedIn: boolean; user?: AuthUser };
}
/** POST /api/v1/auth/register */
export async function register(body: {
email: string;
first_name: string;
last_name: string;
password: string;
username: string;
}): Promise<RegisterResponse> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/register`, {
method: "POST",
headers: { "Content-Type": "application/json", accept: "application/json" },
body: JSON.stringify(body),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
const detail = (err as { detail?: string | string[] }).detail;
const message = Array.isArray(detail) ? detail.join(" ") : detail ?? "Kayıt başarısız";
throw new Error(message);
}
return res.json();
}
/** GET /api/v1/auth/me */
export async function me(accessToken: string): Promise<{ user: AuthUser }> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/me`, {
headers: {
accept: "application/json",
Authorization: `Bearer ${accessToken}`,
},
});
if (!res.ok) throw new Error("Oturum bilgisi alınamadı");
return res.json();
}
/** POST /api/v1/auth/refresh */
export async function refresh(refreshToken: string): Promise<RefreshResponse> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/refresh`, {
method: "POST",
headers: { "Content-Type": "application/json", accept: "application/json" },
body: JSON.stringify({ refresh_token: refreshToken }),
});
if (!res.ok) throw new Error("Token yenilenemedi");
return res.json();
}
const ACCESS_KEY = "auth_access_token";
const REFRESH_KEY = "auth_refresh_token";
const AUTH_CHANGE_EVENT = "auth-change";
/** Header vb. bileşenlerin oturum değişikliğini algılaması için tetiklenir. */
export function notifyAuthChange(): void {
if (typeof window === "undefined") return;
window.dispatchEvent(new Event(AUTH_CHANGE_EVENT));
}
export function setTokens(access: string, refreshToken: string): void {
if (typeof window === "undefined") return;
localStorage.setItem(ACCESS_KEY, access);
localStorage.setItem(REFRESH_KEY, refreshToken);
notifyAuthChange();
}
export function getAccessToken(): string | null {
if (typeof window === "undefined") return null;
return localStorage.getItem(ACCESS_KEY);
}
export function getRefreshToken(): string | null {
if (typeof window === "undefined") return null;
return localStorage.getItem(REFRESH_KEY);
}
export function clearTokens(): void {
if (typeof window === "undefined") return;
localStorage.removeItem(ACCESS_KEY);
localStorage.removeItem(REFRESH_KEY);
notifyAuthChange();
}
export { AUTH_CHANGE_EVENT };