@@ -105,31 +105,38 @@ export function clampSessionExpiry(
105105 */
106106interface ClampableSession {
107107 userId ?: string | null
108- activeOrganizationId ?: string | null
109108 impersonatedBy ?: string | null
110109 createdAt ?: Date | string | null
111110 expiresAt ?: Date | string | null
112111}
113112
114113/**
115114 * Applies the org session policy to a session's proposed `expiresAt` from a
116- * Better Auth database hook. The governing org is the session's
117- * `activeOrganizationId` when present, else the user's membership — the same
118- * resolution the cookie-cache version uses, so every member session
119- * (including ones created before the user joined) is governed consistently.
120- * Returns the original date when no clamp applies: impersonation sessions
121- * are platform-admin tooling with their own short expiry, and non-member
115+ * Better Auth database hook. The governing org is the user's MEMBERSHIP —
116+ * never the session row's `activeOrganizationId`, which goes stale on
117+ * join/leave/transfer — matching the cookie-cache version resolution, so
118+ * every member session (including ones created before the user joined or
119+ * carried across a transfer) is governed consistently. Callers that have
120+ * JUST resolved the membership themselves (the session create hook) pass it
121+ * as `freshMembershipOrgId` to skip the duplicate lookup. Returns the
122+ * original date when no clamp applies: impersonation sessions are
123+ * platform-admin tooling with their own short expiry, and non-member
122124 * sessions have no policy.
123125 */
124- export async function clampExpiryForSession ( session : ClampableSession ) : Promise < Date | undefined > {
126+ export async function clampExpiryForSession (
127+ session : ClampableSession ,
128+ freshMembershipOrgId ?: string | null
129+ ) : Promise < Date | undefined > {
125130 // Better Auth context values can cross a serialization boundary — normalize
126131 // date fields in case they arrive as ISO strings rather than Dates.
127132 const expiresAt = session . expiresAt ? new Date ( session . expiresAt ) : undefined
128133 if ( ! expiresAt || session . impersonatedBy ) {
129134 return expiresAt
130135 }
131136 const organizationId =
132- session . activeOrganizationId ?? ( await getMemberOrganizationId ( session . userId ) )
137+ freshMembershipOrgId !== undefined
138+ ? freshMembershipOrgId
139+ : await getMemberOrganizationId ( session . userId )
133140 if ( ! organizationId ) return expiresAt
134141
135142 const policy = await getSessionPolicy ( organizationId )
0 commit comments