mirror of
https://github.com/open-reception/appointment-booking-software.git
synced 2026-09-12 20:27:39 +02:00
Use old session id from old token for refresh. Refresh offset set to ten minutes.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { SignJWT, jwtVerify, type JWTPayload } from "jose";
|
||||
import { SignJWT, decodeJwt, jwtVerify, type JWTPayload } from "jose";
|
||||
import { env } from "$env/dynamic/private";
|
||||
import type { SelectUser } from "$lib/server/db/central-schema";
|
||||
import { UniversalLogger } from "$lib/logger";
|
||||
@@ -57,6 +57,28 @@ export async function generateRefreshToken(userId: string, sessionId: string): P
|
||||
return jwt;
|
||||
}
|
||||
|
||||
export async function decodeAccessToken(
|
||||
token: string,
|
||||
): Promise<(JWTPayload & { userId: string; sessionId: string }) | null> {
|
||||
try {
|
||||
const payload = await decodeJwt(token);
|
||||
|
||||
return {
|
||||
userId: payload.userId as string,
|
||||
email: payload.email,
|
||||
name: payload.name,
|
||||
role: payload.role as "GLOBAL_ADMIN" | "TENANT_ADMIN" | "STAFF",
|
||||
tenantId: payload.tenantId as string | undefined,
|
||||
sessionId: payload.sessionId as string,
|
||||
iat: payload.iat,
|
||||
exp: payload.exp,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.warn("JWT verification failed:", { error: String(error) });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function verifyAccessToken(
|
||||
token: string,
|
||||
): Promise<(JWTPayload & { userId: string; sessionId: string }) | null> {
|
||||
|
||||
@@ -285,13 +285,13 @@ export class SessionService {
|
||||
logger.info("Expired sessions cleaned up");
|
||||
}
|
||||
|
||||
static async getUserSession(accessToken: string): Promise<SelectUserSession | null> {
|
||||
logger.debug(`Getting active sessions for a given access token`);
|
||||
static async getUserSession(sessionId: string): Promise<SelectUserSession | null> {
|
||||
logger.debug(`Getting active sessions for session id: ${sessionId}`);
|
||||
|
||||
const sessions = await db
|
||||
.select()
|
||||
.from(userSession)
|
||||
.where(eq(userSession.accessToken, accessToken))
|
||||
.where(eq(userSession.id, sessionId))
|
||||
.orderBy(userSession.lastUsedAt);
|
||||
|
||||
return sessions[0] ?? null;
|
||||
|
||||
@@ -3,9 +3,11 @@ import { SessionService } from "$lib/server/auth/session-service";
|
||||
import type { RequestHandler } from "./$types";
|
||||
import { registerOpenAPIRoute } from "$lib/server/openapi";
|
||||
import { UniversalLogger } from "$lib/logger";
|
||||
import { isBefore } from "date-fns";
|
||||
import { isBefore, subMinutes } from "date-fns";
|
||||
import { decodeAccessToken } from "$lib/server/auth/jwt-utils";
|
||||
|
||||
const logger = new UniversalLogger().setContext("AuthRefreshAPI");
|
||||
const REFRESH_OFFSET = 10;
|
||||
|
||||
registerOpenAPIRoute("/auth/refresh", "POST", {
|
||||
summary: "Refresh access token",
|
||||
@@ -68,13 +70,15 @@ export const POST: RequestHandler = async ({ cookies }) => {
|
||||
}
|
||||
|
||||
// Get the (possibly invalid) session from the database
|
||||
const oldSession = await SessionService.getUserSession(accessToken);
|
||||
const decodedToken = await decodeAccessToken(accessToken);
|
||||
const oldSessionId = decodedToken?.sessionId ?? null;
|
||||
const oldSession = oldSessionId ? await SessionService.getUserSession(oldSessionId) : null;
|
||||
|
||||
if (!oldSession) {
|
||||
return json({ error: "No valid session found for user" }, { status: 401 });
|
||||
}
|
||||
|
||||
if (isBefore(oldSession.expiresAt, new Date())) {
|
||||
if (isBefore(oldSession.expiresAt, subMinutes(new Date(), REFRESH_OFFSET))) {
|
||||
return json(
|
||||
{
|
||||
message: "Session still valid, no refresh needed",
|
||||
|
||||
Reference in New Issue
Block a user