Skip to content

Commit 4804b00

Browse files
committed
Cloudwatch picks up session logout events
1 parent fb57aa6 commit 4804b00

2 files changed

Lines changed: 24 additions & 5 deletions

File tree

apps/webapp/app/services/session.server.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import { getUserById } from "~/models/user.server";
33
import { sanitizeRedirectPath } from "~/utils";
44
import { authenticator } from "./auth.server";
55
import { getImpersonationId } from "./impersonation.server";
6-
import { getEffectiveSessionDuration, isSessionExpired } from "./sessionDuration.server";
6+
import { logger } from "./logger.server";
7+
import {
8+
getEffectiveSessionDuration,
9+
getSessionIssuedAt,
10+
isSessionExpired,
11+
} from "./sessionDuration.server";
712
import { getUserSession } from "./sessionStorage.server";
813

914
export async function getUserId(request: Request): Promise<string | undefined> {
@@ -29,8 +34,22 @@ export async function getUserId(request: Request): Promise<string | undefined> {
2934
// by the most restrictive Organization.maxSessionDuration). If the session
3035
// was issued longer ago than the cap allows, force a logout.
3136
const session = await getUserSession(request);
32-
const { durationSeconds } = await getEffectiveSessionDuration(authUser.userId);
37+
const { durationSeconds, orgCapSeconds, userSettingSeconds } = await getEffectiveSessionDuration(
38+
authUser.userId
39+
);
3340
if (isSessionExpired(session, durationSeconds)) {
41+
const issuedAt = getSessionIssuedAt(session);
42+
// HIPAA audit trail: structured log lands in CloudWatch via stdout. Use
43+
// the stable `event` field to filter/aggregate auto-logout events.
44+
logger.info("Auto-logout: session exceeded effective duration", {
45+
event: "session.auto_logout",
46+
userId: authUser.userId,
47+
effectiveDurationSeconds: durationSeconds,
48+
userSettingSeconds,
49+
orgCapSeconds,
50+
sessionAgeMs: issuedAt === null ? null : Date.now() - issuedAt,
51+
requestPath: new URL(request.url).pathname,
52+
});
3453
throw redirect("/logout");
3554
}
3655

apps/webapp/app/services/sessionDuration.server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export function getAllowedSessionOptions(
119119
return allowed;
120120
}
121121

122-
function readSessionIssuedAt(session: Session): number | null {
122+
export function getSessionIssuedAt(session: Session): number | null {
123123
const raw = session.get(SESSION_ISSUED_AT_KEY);
124124
if (typeof raw !== "number" || !Number.isFinite(raw)) return null;
125125
return raw;
@@ -135,7 +135,7 @@ export function isSessionExpired(
135135
effectiveDurationSeconds: number,
136136
now: number = Date.now()
137137
): boolean {
138-
const issuedAt = readSessionIssuedAt(session);
138+
const issuedAt = getSessionIssuedAt(session);
139139
if (issuedAt === null) return false;
140140
return now - issuedAt > effectiveDurationSeconds * 1000;
141141
}
@@ -150,7 +150,7 @@ export function setSessionIssuedAt(session: Session, now: number = Date.now()):
150150
* caller knows to commit the cookie. Returns false when nothing changed.
151151
*/
152152
export function ensureSessionIssuedAt(session: Session, now: number = Date.now()): boolean {
153-
if (readSessionIssuedAt(session) !== null) return false;
153+
if (getSessionIssuedAt(session) !== null) return false;
154154
setSessionIssuedAt(session, now);
155155
return true;
156156
}

0 commit comments

Comments
 (0)