auth-cookies build error fix
This commit is contained in:
parent
7b2b185ed9
commit
514982d009
4 changed files with 213 additions and 133 deletions
|
|
@ -4,7 +4,7 @@ import { NextResponse } from "next/server";
|
|||
export type TokenBundle = {
|
||||
access_token: string;
|
||||
refresh_token?: string;
|
||||
/** Directus returns seconds-until-expiration */
|
||||
/** seconds until expiration (Directus style) */
|
||||
expires?: number;
|
||||
};
|
||||
|
||||
|
|
@ -14,55 +14,89 @@ export type PublicUser = {
|
|||
username: string;
|
||||
};
|
||||
|
||||
export const ACCESS_COOKIE = "ma_access";
|
||||
export const REFRESH_COOKIE = "ma_refresh";
|
||||
const ACCESS_COOKIE = "ma_at";
|
||||
const REFRESH_COOKIE = "ma_rt";
|
||||
const USER_COOKIE = "ma_user";
|
||||
|
||||
/**
|
||||
* Mutates `res` in-place to set auth cookies.
|
||||
* Keeps tokens HttpOnly; sets SameSite=Lax; Secure for HTTPS.
|
||||
*/
|
||||
export function setAuthCookies(
|
||||
res: NextResponse,
|
||||
tokens: TokenBundle,
|
||||
_user?: PublicUser
|
||||
): void {
|
||||
const maxAge =
|
||||
typeof tokens.expires === "number" ? tokens.expires : 60 * 60 * 12; // 12h default
|
||||
|
||||
if (tokens.access_token) {
|
||||
res.cookies.set(ACCESS_COOKIE, tokens.access_token, {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
secure: true,
|
||||
path: "/",
|
||||
maxAge,
|
||||
});
|
||||
}
|
||||
|
||||
if (tokens.refresh_token) {
|
||||
// If Directus doesn’t give a separate TTL, just make it longer than access (fallback 30d)
|
||||
const refreshMaxAge =
|
||||
typeof tokens.expires === "number" ? tokens.expires * 4 : 60 * 60 * 24 * 30;
|
||||
|
||||
res.cookies.set(REFRESH_COOKIE, tokens.refresh_token, {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
secure: true,
|
||||
path: "/",
|
||||
maxAge: refreshMaxAge,
|
||||
});
|
||||
/** Derive cookie maxAge (in seconds) for access token */
|
||||
function accessMaxAgeSec(expires?: number) {
|
||||
// If Directus gave us seconds-until-expiration, use that (clamped)
|
||||
if (typeof expires === "number" && Number.isFinite(expires)) {
|
||||
return Math.max(60, Math.min(expires, 60 * 60 * 24)); // 1 min .. 1 day
|
||||
}
|
||||
// Fallback: 1 hour
|
||||
return 60 * 60;
|
||||
}
|
||||
|
||||
/** Mutates `res` in-place to clear both auth cookies. */
|
||||
export function clearAuthCookies(res: NextResponse): void {
|
||||
const opts = {
|
||||
httpOnly: true,
|
||||
/** Refresh token lifetime: default ~30 days if present */
|
||||
function refreshMaxAgeSec() {
|
||||
return 60 * 60 * 24 * 30;
|
||||
}
|
||||
|
||||
/** Shared secure cookie options (override per cookie when needed) */
|
||||
function baseOpts(maxAge: number) {
|
||||
return {
|
||||
httpOnly: true as const,
|
||||
sameSite: "lax" as const,
|
||||
secure: true,
|
||||
path: "/",
|
||||
maxAge: 0, // expire immediately
|
||||
maxAge,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set auth cookies on the provided response.
|
||||
* Returns the SAME response instance with cookies set (typed generically).
|
||||
*/
|
||||
export function setAuthCookies<T>(
|
||||
res: NextResponse<T>,
|
||||
tokens: TokenBundle,
|
||||
user?: PublicUser
|
||||
): NextResponse<T> {
|
||||
// Access token (httpOnly)
|
||||
const atAge = accessMaxAgeSec(tokens.expires);
|
||||
res.cookies.set(ACCESS_COOKIE, tokens.access_token, baseOpts(atAge));
|
||||
|
||||
// Refresh token (httpOnly) if present
|
||||
if (tokens.refresh_token) {
|
||||
res.cookies.set(REFRESH_COOKIE, tokens.refresh_token, baseOpts(refreshMaxAgeSec()));
|
||||
}
|
||||
|
||||
// Small readable user stub (NOT httpOnly) so client can reflect UI state if desired
|
||||
if (user) {
|
||||
const safeStub = JSON.stringify({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
});
|
||||
res.cookies.set(USER_COOKIE, safeStub, {
|
||||
...baseOpts(atAge),
|
||||
httpOnly: false, // readable on client
|
||||
});
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Clear all auth cookies (returns the SAME response instance) */
|
||||
export function clearAuthCookies<T>(res: NextResponse<T>): NextResponse<T> {
|
||||
const opts = {
|
||||
httpOnly: true as const,
|
||||
sameSite: "lax" as const,
|
||||
secure: true,
|
||||
path: "/",
|
||||
maxAge: 0,
|
||||
};
|
||||
res.cookies.set(ACCESS_COOKIE, "", opts);
|
||||
res.cookies.set(REFRESH_COOKIE, "", opts);
|
||||
// Also clear public user stub
|
||||
res.cookies.set(USER_COOKIE, "", { ...opts, httpOnly: false });
|
||||
return res;
|
||||
}
|
||||
|
||||
/** (Optional) Simple helpers if you ever want the names elsewhere */
|
||||
export const AUTH_COOKIE_KEYS = {
|
||||
access: ACCESS_COOKIE,
|
||||
refresh: REFRESH_COOKIE,
|
||||
user: USER_COOKIE,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue