Refactor session management and enhance OAuth2 callback handling
- Updated session management functions to include cookie handling for session creation and destruction. - Introduced applySessionCookie and clearSessionCookie functions for better cookie management in responses. - Enhanced error logging in the OAuth2 callback to improve debugging. - Revised PHASE-TRACKING.md to reflect changes in session handling and OAuth2 integration.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { createHmac, randomBytes, timingSafeEqual } from 'crypto';
|
||||
import { cookies } from 'next/headers';
|
||||
import type { NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { SessionUserSchema } from '@nexumi/shared';
|
||||
import { env } from './env';
|
||||
@@ -52,20 +53,41 @@ function sessionRedisKey(sessionId: string): string {
|
||||
return `${SESSION_KEY_PREFIX}${sessionId}`;
|
||||
}
|
||||
|
||||
export async function createSession(payload: SessionPayload): Promise<void> {
|
||||
const sessionId = randomBytes(32).toString('hex');
|
||||
await redis.set(sessionRedisKey(sessionId), JSON.stringify(payload), 'EX', SESSION_TTL_SECONDS);
|
||||
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set(SESSION_COOKIE_NAME, buildCookieValue(sessionId), {
|
||||
/** Secure cookies only when the public WebUI URL is HTTPS (HTTP IP deploys must not use Secure). */
|
||||
export function sessionCookieOptions(): {
|
||||
httpOnly: boolean;
|
||||
sameSite: 'lax';
|
||||
secure: boolean;
|
||||
path: string;
|
||||
maxAge: number;
|
||||
} {
|
||||
return {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
secure: env.NODE_ENV === 'production',
|
||||
secure: env.WEBUI_URL.startsWith('https://'),
|
||||
path: '/',
|
||||
maxAge: SESSION_TTL_SECONDS
|
||||
};
|
||||
}
|
||||
|
||||
export function applySessionCookie(response: NextResponse, cookieValue: string): void {
|
||||
response.cookies.set(SESSION_COOKIE_NAME, cookieValue, sessionCookieOptions());
|
||||
}
|
||||
|
||||
export function clearSessionCookie(response: NextResponse): void {
|
||||
response.cookies.set(SESSION_COOKIE_NAME, '', {
|
||||
...sessionCookieOptions(),
|
||||
maxAge: 0
|
||||
});
|
||||
}
|
||||
|
||||
/** Persists the session in Redis and returns the signed cookie value to attach to a response. */
|
||||
export async function createSession(payload: SessionPayload): Promise<string> {
|
||||
const sessionId = randomBytes(32).toString('hex');
|
||||
await redis.set(sessionRedisKey(sessionId), JSON.stringify(payload), 'EX', SESSION_TTL_SECONDS);
|
||||
return buildCookieValue(sessionId);
|
||||
}
|
||||
|
||||
export async function getSession(): Promise<SessionPayload | null> {
|
||||
const cookieStore = await cookies();
|
||||
const raw = cookieStore.get(SESSION_COOKIE_NAME)?.value;
|
||||
@@ -93,7 +115,6 @@ export async function destroySession(): Promise<void> {
|
||||
await redis.del(sessionRedisKey(sessionId));
|
||||
}
|
||||
}
|
||||
cookieStore.delete(SESSION_COOKIE_NAME);
|
||||
}
|
||||
|
||||
export async function requireSession(): Promise<SessionPayload> {
|
||||
|
||||
Reference in New Issue
Block a user