RJBULK-APP/lib/auth.ts

74 lines
1.8 KiB
TypeScript
Raw Normal View History

import { cookies } from "next/headers";
import { PB_URL } from "./pocketbase";
import type { AppUser } from "./types";
const COOKIE_NAME = "pb_auth";
const COOKIE_MAX_AGE = 60 * 60 * 24 * 7; // 7 days
export interface AuthState {
user: AppUser | null;
token: string | null;
}
/**
* Server-side auth: read the PB token from the cookie and verify it against
* the PB API. We use plain fetch (not the PocketBase SDK) to avoid Next.js
* RSC's auto-cancellation of the SDK's internal fetch.
*/
export async function getAuth(): Promise<AuthState> {
const cookieStore = await cookies();
const cookie = cookieStore.get(COOKIE_NAME);
if (!cookie?.value) return { user: null, token: null };
try {
const res = await fetch(`${PB_URL}/api/collections/users/auth-refresh`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: cookie.value,
},
cache: "no-store",
});
if (!res.ok) {
return { user: null, token: null };
}
const data = await res.json();
const record = data.record;
return {
user: {
id: record.id,
email: record.email,
name: record.name,
verified: record.verified,
},
token: cookie.value,
};
} catch {
return { user: null, token: null };
}
}
export async function requireAuth(): Promise<AuthState> {
const auth = await getAuth();
if (!auth.user) {
throw new Error("Unauthorized");
}
return auth;
}
export async function setAuthCookie(token: string) {
const cookieStore = await cookies();
cookieStore.set(COOKIE_NAME, token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
path: "/",
maxAge: COOKIE_MAX_AGE,
});
}
export async function clearAuthCookie() {
const cookieStore = await cookies();
cookieStore.delete(COOKIE_NAME);
}