general: console cleanup

This commit is contained in:
Michael Freno
2026-01-12 00:24:24 -05:00
parent 55b914cb40
commit ed16b277f7
3 changed files with 24 additions and 308 deletions

View File

@@ -136,12 +136,9 @@ export async function attemptTokenRefresh(
refreshToken: string
): Promise<string | null> {
try {
console.log("[Token Refresh SSR] Attempting server-side refresh");
// Step 1: Get current session from Vinxi
const session = await getAuthSession(event);
if (!session) {
console.warn("[Token Refresh SSR] No valid session found");
return null;
}
@@ -149,10 +146,6 @@ export async function attemptTokenRefresh(
const clientIP = getClientIP(event);
const userAgent = getUserAgent(event);
// Step 3: Rotate session (includes validation, breach detection, cookie update)
console.log(
`[Token Refresh SSR] Rotating tokens for session ${session.sessionId}`
);
const newSession = await rotateAuthSession(
event,
session,
@@ -161,14 +154,11 @@ export async function attemptTokenRefresh(
);
if (!newSession) {
console.warn("[Token Refresh SSR] Token rotation failed");
return null;
}
console.log("[Token Refresh SSR] Token refresh successful");
return newSession.userId;
} catch (error) {
console.error("[Token Refresh SSR] Error:", error);
return null;
}
}
@@ -179,13 +169,7 @@ export const authRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const { code } = input;
console.log(
"[GitHub Callback] Starting OAuth flow with code:",
code.substring(0, 10) + "..."
);
try {
console.log("[GitHub Callback] Exchanging code for access token...");
const tokenResponse = await fetchWithTimeout(
"https://github.com/login/oauth/access_token",
{
@@ -214,9 +198,6 @@ export const authRouter = createTRPCRouter({
});
}
console.log(
"[GitHub Callback] Access token received, fetching user data..."
);
const userResponse = await fetchWithTimeout(
"https://api.github.com/user",
{
@@ -232,9 +213,6 @@ export const authRouter = createTRPCRouter({
const login = user.login;
const icon = user.avatar_url;
console.log("[GitHub Callback] User data received:", { login });
console.log("[GitHub Callback] Fetching user emails...");
const emailsResponse = await fetchWithTimeout(
"https://api.github.com/user/emails",
{
@@ -255,40 +233,20 @@ export const authRouter = createTRPCRouter({
const email = primaryEmail?.email || null;
const emailVerified = primaryEmail?.verified || false;
console.log(
"[GitHub Callback] Primary email:",
email,
"verified:",
emailVerified
);
const conn = ConnectionFactory();
console.log("[GitHub Callback] Checking if user exists...");
// Strategy 1: Check if this GitHub identity already linked
let userId = await findUserByProvider("github", login);
let isNewUser = false;
let isLinkedAccount = false;
if (userId) {
console.log(
"[GitHub Callback] Existing GitHub provider found:",
userId
);
// Update provider info
await updateProviderLastUsed(userId, "github");
} else {
// Strategy 2: Check if email matches existing user (account linking)
if (email) {
userId = await findUserByEmail(email);
if (userId) {
console.log(
"[GitHub Callback] Found existing user by email, linking GitHub account:",
userId
);
// Link GitHub to existing account
try {
await linkProvider(userId, "github", {
providerUserId: login,
@@ -298,10 +256,6 @@ export const authRouter = createTRPCRouter({
});
isLinkedAccount = true;
} catch (linkError: any) {
console.error(
"[GitHub Callback] Failed to link provider:",
linkError.message
);
throw new TRPCError({
code: "CONFLICT",
message: linkError.message
@@ -313,7 +267,6 @@ export const authRouter = createTRPCRouter({
// Strategy 3: Create new user
if (!userId) {
userId = uuidV4();
console.log("[GitHub Callback] Creating new user:", userId);
const insertQuery = `INSERT INTO User (id, email, email_verified, display_name, provider, image) VALUES (?, ?, ?, ?, ?, ?)`;
const insertParams = [
@@ -337,16 +290,11 @@ export const authRouter = createTRPCRouter({
});
isNewUser = true;
console.log("[GitHub Callback] New user created");
} catch (insertError: any) {
if (
insertError.code === "SQLITE_CONSTRAINT" &&
insertError.message?.includes("User.email")
) {
console.error(
"[GitHub Callback] Email conflict during insert:",
email
);
throw new TRPCError({
code: "CONFLICT",
message:
@@ -360,8 +308,6 @@ export const authRouter = createTRPCRouter({
const isAdmin = userId === env.ADMIN_ID;
console.log("[GitHub Callback] Creating session for user:", userId);
// Create session with Vinxi (OAuth defaults to remember me)
const clientIP = getClientIP(getH3Event(ctx));
const userAgent = getUserAgent(getH3Event(ctx));
await createAuthSession(
@@ -372,13 +318,8 @@ export const authRouter = createTRPCRouter({
clientIP,
userAgent
);
// Set CSRF token for authenticated session
setCSRFToken(getH3Event(ctx));
console.log("[GitHub Callback] Session created successfully");
// Log successful OAuth login
await logAuditEvent({
userId,
eventType: "auth.login.success",
@@ -392,7 +333,6 @@ export const authRouter = createTRPCRouter({
success: true
});
console.log("[GitHub Callback] OAuth flow completed successfully");
return {
success: true,
redirectTo: "/account"
@@ -454,13 +394,7 @@ export const authRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const { code } = input;
console.log(
"[Google Callback] Starting OAuth flow with code:",
code.substring(0, 10) + "..."
);
try {
console.log("[Google Callback] Exchanging code for access token...");
const tokenResponse = await fetchWithTimeout(
"https://oauth2.googleapis.com/token",
{
@@ -490,9 +424,6 @@ export const authRouter = createTRPCRouter({
});
}
console.log(
"[Google Callback] Access token received, fetching user data..."
);
const userResponse = await fetchWithTimeout(
"https://www.googleapis.com/oauth2/v3/userinfo",
{
@@ -509,39 +440,19 @@ export const authRouter = createTRPCRouter({
const image = userData.picture;
const email = userData.email;
const email_verified = userData.email_verified;
console.log("[Google Callback] User data received:", {
name,
email,
email_verified
});
const conn = ConnectionFactory();
console.log("[Google Callback] Checking if user exists...");
// Strategy 1: Check if this Google identity already linked
let userId = await findUserByProvider("google", email);
let isNewUser = false;
let isLinkedAccount = false;
if (userId) {
console.log(
"[Google Callback] Existing Google provider found:",
userId
);
// Update provider info
await updateProviderLastUsed(userId, "google");
} else {
// Strategy 2: Check if email matches existing user (account linking)
userId = await findUserByEmail(email);
if (userId) {
console.log(
"[Google Callback] Found existing user by email, linking Google account:",
userId
);
// Link Google to existing account
try {
await linkProvider(userId, "google", {
providerUserId: email,
@@ -562,10 +473,8 @@ export const authRouter = createTRPCRouter({
}
}
// Strategy 3: Create new user
if (!userId) {
userId = uuidV4();
console.log("[Google Callback] Creating new user:", userId);
const insertQuery = `INSERT INTO User (id, email, email_verified, display_name, provider, image) VALUES (?, ?, ?, ?, ?, ?)`;
const insertParams = [
@@ -592,7 +501,6 @@ export const authRouter = createTRPCRouter({
});
isNewUser = true;
console.log("[Google Callback] New user created");
} catch (insertError: any) {
if (
insertError.code === "SQLITE_CONSTRAINT" &&
@@ -615,7 +523,6 @@ export const authRouter = createTRPCRouter({
const isAdmin = userId === env.ADMIN_ID;
console.log("[Google Callback] Creating session for user:", userId);
// Create session with Vinxi (OAuth defaults to remember me)
const clientIP = getClientIP(getH3Event(ctx));
const userAgent = getUserAgent(getH3Event(ctx));
@@ -628,12 +535,8 @@ export const authRouter = createTRPCRouter({
userAgent
);
// Set CSRF token for authenticated session
setCSRFToken(getH3Event(ctx));
console.log("[Google Callback] Session created successfully");
// Log successful OAuth login
await logAuditEvent({
userId,
eventType: "auth.login.success",
@@ -647,7 +550,6 @@ export const authRouter = createTRPCRouter({
success: true
});
console.log("[Google Callback] OAuth flow completed successfully");
return {
success: true,
redirectTo: "/account"
@@ -655,7 +557,6 @@ export const authRouter = createTRPCRouter({
} catch (error) {
console.error("[Google Callback] Error during OAuth flow:", error);
// Log failed OAuth login
const { ipAddress, userAgent } = getAuditContext(getH3Event(ctx));
await logAuditEvent({
eventType: "auth.login.failed",
@@ -716,17 +617,9 @@ export const authRouter = createTRPCRouter({
const { email, token } = input;
try {
console.log("[Email Login] Attempting login for:", email);
const secret = new TextEncoder().encode(env.JWT_SECRET_KEY);
const { payload } = await jwtVerify(token, secret);
console.log("[Email Login] JWT verified successfully. Payload:", {
email: payload.email,
rememberMe: payload.rememberMe,
exp: payload.exp
});
if (payload.email !== email) {
console.error("[Email Login] Email mismatch:", {
payloadEmail: payload.email,
@@ -738,9 +631,7 @@ export const authRouter = createTRPCRouter({
});
}
// Use rememberMe from JWT payload (source of truth), default to false
const rememberMe = (payload.rememberMe as boolean) ?? false;
console.log("[Email Login] Using rememberMe from JWT:", rememberMe);
const conn = ConnectionFactory();
const query = `SELECT * FROM User WHERE email = ?`;
@@ -758,13 +649,9 @@ export const authRouter = createTRPCRouter({
const userId = (res.rows[0] as unknown as User).id;
const isAdmin = userId === env.ADMIN_ID;
console.log("[Email Login] User found:", { userId, isAdmin });
// Create session with Vinxi (handles DB + encrypted cookie)
const clientIP = getClientIP(getH3Event(ctx));
const userAgent = getUserAgent(getH3Event(ctx));
console.log("[Email Login] Creating auth session...");
await createAuthSession(
getH3Event(ctx),
userId,
@@ -773,13 +660,8 @@ export const authRouter = createTRPCRouter({
clientIP,
userAgent
);
// Set CSRF token for authenticated session
setCSRFToken(getH3Event(ctx));
console.log("[Email Login] Session created successfully");
// Log successful email link login
await logAuditEvent({
userId,
eventType: "auth.login.success",
@@ -837,13 +719,6 @@ export const authRouter = createTRPCRouter({
const { email, code, rememberMe } = input;
try {
console.log(
"[Email Code Login] Attempting login for:",
email,
"with code:",
code
);
const conn = ConnectionFactory();
const res = await conn.execute({
sql: "SELECT * FROM User WHERE email = ?",
@@ -911,9 +786,6 @@ export const authRouter = createTRPCRouter({
const shouldRemember =
rememberMe ?? (payload.rememberMe as boolean) ?? false;
console.log("[Email Code Login] Code verified, creating session");
// Create session
const clientIP = getClientIP(getH3Event(ctx));
const userAgent = getUserAgent(getH3Event(ctx));
await createAuthSession(
@@ -924,13 +796,8 @@ export const authRouter = createTRPCRouter({
clientIP,
userAgent
);
// Set CSRF token
setCSRFToken(getH3Event(ctx));
console.log("[Email Code Login] Session created successfully");
// Log successful code login
await logAuditEvent({
userId,
eventType: "auth.login.success",
@@ -1840,11 +1707,8 @@ export const authRouter = createTRPCRouter({
const session = await getAuthSession(getH3Event(ctx));
if (session) {
// Step 2: Revoke entire token family (all devices)
await revokeTokenFamily(session.tokenFamily, "user_logout");
console.log(`Token family ${session.tokenFamily} revoked on signout`);
// Step 3: Log signout event
const { ipAddress, userAgent } = getAuditContext(getH3Event(ctx));
await logAuditEvent({
userId: session.userId,

View File

@@ -8,7 +8,7 @@ import { v4 as uuidV4 } from "uuid";
export async function migrateMultiAuth() {
const conn = ConnectionFactory();
console.log("[Migration] Starting multi-auth migration...");
try {
// Step 1: Check if UserProvider table exists
@@ -17,11 +17,9 @@ export async function migrateMultiAuth() {
});
if (tableCheck.rows.length > 0) {
console.log(
"[Migration] UserProvider table already exists, skipping creation"
);
} else {
console.log("[Migration] Creating UserProvider table...");
await conn.execute(`
CREATE TABLE UserProvider (
id TEXT PRIMARY KEY,
@@ -37,7 +35,7 @@ export async function migrateMultiAuth() {
)
`);
console.log("[Migration] Creating UserProvider indexes...");
await conn.execute(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_user_provider_provider_user ON UserProvider (provider, provider_user_id)"
);
@@ -64,11 +62,9 @@ export async function migrateMultiAuth() {
);
if (hasDeviceName) {
console.log(
"[Migration] Session table already has device columns, skipping"
);
} else {
console.log("[Migration] Adding device columns to Session table...");
await conn.execute("ALTER TABLE Session ADD COLUMN device_name TEXT");
await conn.execute("ALTER TABLE Session ADD COLUMN device_type TEXT");
await conn.execute("ALTER TABLE Session ADD COLUMN browser TEXT");
@@ -79,14 +75,12 @@ export async function migrateMultiAuth() {
await conn.execute("ALTER TABLE Session ADD COLUMN last_active_at TEXT");
// Update existing rows to set last_active_at = last_used
console.log(
"[Migration] Updating existing sessions with last_active_at..."
);
await conn.execute(
"UPDATE Session SET last_active_at = COALESCE(last_used, created_at) WHERE last_active_at IS NULL"
);
console.log("[Migration] Creating Session indexes...");
await conn.execute(
"CREATE INDEX IF NOT EXISTS idx_session_last_active ON Session (last_active_at)"
);
@@ -96,14 +90,12 @@ export async function migrateMultiAuth() {
}
// Step 3: Migrate existing users to UserProvider table
console.log("[Migration] Checking for users to migrate...");
const usersResult = await conn.execute({
sql: "SELECT id, email, provider, display_name, image, apple_user_string FROM User WHERE provider IS NOT NULL"
});
console.log(
`[Migration] Found ${usersResult.rows.length} users to migrate`
);
let migratedCount = 0;
for (const row of usersResult.rows) {
@@ -111,9 +103,7 @@ export async function migrateMultiAuth() {
// Skip apple provider users (they're for Life and Lineage mobile app, not website auth)
if (user.provider === "apple") {
console.log(
`[Migration] Skipping user ${user.id} with apple provider (mobile app only)`
);
continue;
}
@@ -124,9 +114,7 @@ export async function migrateMultiAuth() {
});
if (existingProvider.rows.length > 0) {
console.log(
`[Migration] User ${user.id} already migrated, skipping`
);
continue;
}
@@ -198,34 +186,30 @@ export async function migrateMultiAuth() {
}
}
console.log(`[Migration] Migrated ${migratedCount} users successfully`);
// Step 4: Verification
console.log("[Migration] Running verification queries...");
const providerCount = await conn.execute({
sql: "SELECT COUNT(*) as count FROM UserProvider"
});
console.log(
`[Migration] Total providers in UserProvider table: ${(providerCount.rows[0] as any).count}`
);
const multiProviderUsers = await conn.execute({
sql: `SELECT COUNT(*) as count FROM (
SELECT user_id FROM UserProvider GROUP BY user_id HAVING COUNT(*) > 1
)`
});
console.log(
`[Migration] Users with multiple providers: ${(multiProviderUsers.rows[0] as any).count}`
);
console.log("[Migration] Multi-auth migration completed successfully!");
return {
success: true,
migratedUsers: migratedCount,
totalProviders: (providerCount.rows[0] as any).count
};
} catch (error) {
console.error("[Migration] Migration failed:", error);
throw error;
}
}
@@ -234,11 +218,11 @@ export async function migrateMultiAuth() {
if (require.main === module) {
migrateMultiAuth()
.then((result) => {
console.log("[Migration] Result:", result);
process.exit(0);
})
.catch((error) => {
console.error("[Migration] Error:", error);
process.exit(1);
});
}

View File

@@ -201,48 +201,14 @@ export async function createAuthSession(
: undefined // Session cookie (expires on browser close)
};
console.log("[Session Create] Creating session with data:", {
userId: sessionData.userId,
sessionId: sessionData.sessionId,
tokenFamily: sessionData.tokenFamily,
rememberMe: sessionData.rememberMe,
maxAge: configWithMaxAge.maxAge
});
// Use updateSession to set session data directly
console.log(
"[Session Create] Input sessionData:",
JSON.stringify(sessionData, null, 2)
);
const session = await updateSession(event, configWithMaxAge, sessionData);
console.log(
"[Session Create] Returned session object:",
JSON.stringify(
{
id: session.id,
data: session.data,
createdAt: session.createdAt
},
null,
2
)
);
// Explicitly seal/flush the session to ensure cookie is written
// This is important in serverless environments where response might stream early
const { sealSession } = await import("vinxi/http");
sealSession(event, configWithMaxAge);
console.log("[Session Create] Explicitly sealed session cookie");
console.log("[Session Create] Session created via updateSession API:", {
sessionId: session.id,
hasData: !!session.data,
dataKeys: session.data ? Object.keys(session.data) : [],
dataIsEmpty: session.data && Object.keys(session.data).length === 0,
inputDataKeys: Object.keys(sessionData),
configPassword: configWithMaxAge.password?.substring(0, 10) + "...",
configMaxAge: configWithMaxAge.maxAge
});
// Set a separate sessionId cookie for DB fallback (in case main session cookie fails)
setCookie(event, "session_id", sessionId, {
@@ -253,29 +219,16 @@ export async function createAuthSession(
maxAge: configWithMaxAge.maxAge
});
console.log("[Session Create] Set session_id fallback cookie:", sessionId);
// Verify session was actually set by reading it back
try {
const cookieName = sessionConfig.name || "session";
const cookieValue = getCookie(event, cookieName);
console.log("[Session Create] Immediate verification:", {
cookieName,
hasCookie: !!cookieValue,
cookieLength: cookieValue?.length || 0
});
// Try reading back the session immediately using the same config
const verifySession = await getSession<SessionData>(
event,
configWithMaxAge
);
console.log("[Session Create] Read-back verification:", {
hasData: !!verifySession.data,
dataMatches: verifySession.data?.userId === sessionData.userId,
userId: verifySession.data?.userId,
sessionId: verifySession.data?.sessionId
});
} catch (verifyError) {
console.error("[Session Create] Failed to verify session:", verifyError);
}
@@ -314,12 +267,7 @@ export async function getAuthSession(
const { unsealSession } = await import("vinxi/http");
const cookieName = sessionConfig.name || "session";
const cookieValue = getCookie(event, cookieName);
console.log(
"[Session Get] skipUpdate mode, cookieName:",
cookieName,
"has cookie:",
!!cookieValue
);
if (!cookieValue) {
return null;
}
@@ -327,42 +275,21 @@ export async function getAuthSession(
try {
// unsealSession returns Partial<Session<T>>, not T directly
const session = await unsealSession(event, sessionConfig, cookieValue);
console.log("[Session Get] Unsealed session:", {
hasData: !!session?.data,
dataType: typeof session?.data,
dataKeys: session?.data ? Object.keys(session.data) : []
});
if (!session?.data || typeof session.data !== "object") {
console.log("[Session Get] Invalid session structure");
return null;
}
const data = session.data as SessionData;
console.log("[Session Get] Session data:", {
hasUserId: !!data.userId,
hasSessionId: !!data.sessionId,
hasRefreshToken: !!data.refreshToken
});
if (!data.userId || !data.sessionId) {
console.log("[Session Get] Missing userId or sessionId");
// Fallback: Try to restore from DB using session_id cookie
const sessionIdCookie = getCookie(event, "session_id");
if (sessionIdCookie) {
console.log(
"[Session Get] Attempting DB fallback (skipUpdate path) with session_id:",
sessionIdCookie
);
const restored = await restoreSessionFromDB(event, sessionIdCookie);
if (restored) {
console.log(
"[Session Get] Successfully restored session from DB (skipUpdate path)"
);
return restored;
}
console.log("[Session Get] DB fallback failed (skipUpdate path)");
}
return null;
@@ -375,7 +302,6 @@ export async function getAuthSession(
data.refreshToken
);
console.log("[Session Get] DB validation result:", isValid);
return isValid ? data : null;
} catch (err) {
console.error("[Session Get] Error in skipUpdate path:", err);
@@ -384,34 +310,17 @@ export async function getAuthSession(
}
// Normal path - allow session updates
console.log("[Session Get] Normal path, getting session");
const session = await getSession<SessionData>(event, sessionConfig);
console.log("[Session Get] Got session:", {
hasData: !!session.data,
dataType: typeof session.data,
dataKeys: session.data ? Object.keys(session.data) : []
});
if (!session.data || !session.data.userId || !session.data.sessionId) {
console.log(
"[Session Get] Missing data or userId/sessionId in normal path"
);
// Fallback: Try to restore from DB using session_id cookie
const sessionIdCookie = getCookie(event, "session_id");
if (sessionIdCookie) {
console.log(
"[Session Get] Attempting DB fallback with session_id:",
sessionIdCookie
);
const restored = await restoreSessionFromDB(event, sessionIdCookie);
if (restored) {
console.log("[Session Get] Successfully restored session from DB");
return restored;
}
console.log(
"[Session Get] DB fallback failed - session not found or invalid"
);
}
return null;
@@ -443,9 +352,6 @@ export async function getAuthSession(
// If headers already sent, we can't read the session cookie properly
// This can happen in SSR when response streaming has started
if (error?.code === "ERR_HTTP_HEADERS_SENT") {
console.warn(
"Cannot access session - headers already sent, retrying with skipUpdate"
);
// Retry with skipUpdate
return getAuthSession(event, true);
}
@@ -479,7 +385,6 @@ async function restoreSessionFromDB(
});
if (result.rows.length === 0) {
console.log("[Session Restore] Session not found in DB:", sessionId);
return null;
}
@@ -487,21 +392,16 @@ async function restoreSessionFromDB(
// Validate session is still valid
if (dbSession.revoked === 1) {
console.log("[Session Restore] Session is revoked");
return null;
}
const expiresAt = new Date(dbSession.expires_at as string);
if (expiresAt < new Date()) {
console.log("[Session Restore] Session expired");
return null;
}
// We can't restore the refresh token (it's hashed in DB)
// So we need to generate a new one and rotate the session
console.log(
"[Session Restore] Session valid but refresh token lost - rotating session"
);
// Get IP and user agent
const { getRequestIP } = await import("vinxi/http");
@@ -520,10 +420,6 @@ async function restoreSessionFromDB(
dbSession.token_family as string // Reuse family
);
console.log(
"[Session Restore] Created new session via rotation:",
newSession.sessionId
);
return newSession;
} catch (error) {
console.error("[Session Restore] Error restoring session:", error);
@@ -606,7 +502,6 @@ export async function invalidateAuthSession(
sessionId: string
): Promise<void> {
const conn = ConnectionFactory();
console.log(`[Session] Invalidating session ${sessionId}`);
await conn.execute({
sql: "UPDATE Session SET revoked = 1 WHERE id = ?",
@@ -644,9 +539,7 @@ export async function revokeTokenFamily(
});
// Revoke all sessions in family
console.log(
`[Token Family] Revoking entire family ${tokenFamily} (reason: ${reason}). Sessions affected: ${sessions.rows.length}`
);
await conn.execute({
sql: "UPDATE Session SET revoked = 1 WHERE token_family = ?",
args: [tokenFamily]
@@ -665,8 +558,6 @@ export async function revokeTokenFamily(
success: true
});
}
console.warn(`Token family ${tokenFamily} revoked: ${reason}`);
}
/**
@@ -699,16 +590,10 @@ export async function detectTokenReuse(sessionId: string): Promise<boolean> {
// Grace period for race conditions
if (timeSinceRotation < AUTH_CONFIG.REFRESH_TOKEN_REUSE_WINDOW_MS) {
console.warn(
`[Token Reuse] Within grace period (${timeSinceRotation}ms < ${AUTH_CONFIG.REFRESH_TOKEN_REUSE_WINDOW_MS}ms), allowing for session ${sessionId}`
);
return false;
}
// Reuse detected outside grace period - this is a breach!
console.error(
`[Token Reuse] BREACH DETECTED! Session ${sessionId} rotated ${timeSinceRotation}ms ago. Child session: ${childSession.id}`
);
// Get token family and revoke entire family
const sessionInfo = await conn.execute({
@@ -755,10 +640,6 @@ export async function rotateAuthSession(
ipAddress: string,
userAgent: string
): Promise<SessionData | null> {
console.log(
`[Token Rotation] Starting rotation for session ${oldSessionData.sessionId}`
);
// Validate old session exists in DB
const isValid = await validateSessionInDB(
oldSessionData.sessionId,
@@ -767,18 +648,12 @@ export async function rotateAuthSession(
);
if (!isValid) {
console.warn(
`[Token Rotation] Invalid session during rotation for ${oldSessionData.sessionId}`
);
return null;
}
// Detect token reuse (breach detection)
const reuseDetected = await detectTokenReuse(oldSessionData.sessionId);
if (reuseDetected) {
console.error(
`[Token Rotation] Token reuse detected for session ${oldSessionData.sessionId}`
);
return null;
}
@@ -795,9 +670,6 @@ export async function rotateAuthSession(
const rotationCount = sessionCheck.rows[0].rotation_count as number;
if (rotationCount >= AUTH_CONFIG.MAX_ROTATION_COUNT) {
console.warn(
`[Token Rotation] Max rotation count reached for session ${oldSessionData.sessionId}`
);
await invalidateAuthSession(event, oldSessionData.sessionId);
return null;
}
@@ -833,9 +705,5 @@ export async function rotateAuthSession(
success: true
});
console.log(
`[Token Rotation] Successfully rotated session ${oldSessionData.sessionId} -> ${newSessionData.sessionId}`
);
return newSessionData;
}