Skip to content

Commit c8950d8

Browse files
committed
fix: check specific session by token hash instead of any user session
The JWT verify was checking if the user has ANY active session, which allowed access even if the SPECIFIC session for this token was terminated. Now correctly: 1. Hash the token to find the specific session 2. If that session is terminatedManually: true → BLOCK 3. If that session is active → allow 4. If that session is inactive but not manually terminated → reactivate 5. Fallback: check if user has any other active sessions (backward compat)
1 parent 168d509 commit c8950d8

1 file changed

Lines changed: 56 additions & 31 deletions

File tree

server/src/bootstrap.js

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -611,8 +611,11 @@ async function registerSessionAwareAuthStrategy(strapi, log) {
611611
const config = strapi.config.get('plugin::magic-sessionmanager') || {};
612612
const strictMode = config.strictSessionEnforcement === true;
613613

614-
// Now check if user has active session
614+
// Now check if THIS SPECIFIC session (by token hash) is valid
615615
try {
616+
// Hash the token to find the specific session
617+
const tokenHashValue = hashToken(token);
618+
616619
// Get user documentId
617620
let userDocId = null;
618621

@@ -631,47 +634,34 @@ async function registerSessionAwareAuthStrategy(strapi, log) {
631634
return decoded;
632635
}
633636

634-
// Check for active sessions first
635-
const activeSessions = await strapi.documents(SESSION_UID).findMany({
637+
// Find THIS SPECIFIC session by token hash
638+
const thisSession = await strapi.documents(SESSION_UID).findFirst({
636639
filters: {
637640
user: { documentId: userDocId },
638-
isActive: true,
641+
tokenHash: tokenHashValue,
639642
},
640-
limit: 1,
643+
fields: ['documentId', 'isActive', 'terminatedManually', 'lastActive'],
641644
});
642645

643-
// If active session exists, all good
644-
if (activeSessions && activeSessions.length > 0) {
645-
return decoded;
646-
}
647-
648-
// No active session - check for inactive sessions
649-
const inactiveSessions = await strapi.documents(SESSION_UID).findMany({
650-
filters: {
651-
user: { documentId: userDocId },
652-
isActive: false,
653-
},
654-
limit: 5,
655-
fields: ['documentId', 'terminatedManually', 'lastActive'],
656-
sort: [{ lastActive: 'desc' }],
657-
});
658-
659-
if (inactiveSessions && inactiveSessions.length > 0) {
660-
// Check if ANY session was manually terminated
661-
const manuallyTerminated = inactiveSessions.find(s => s.terminatedManually === true);
646+
if (thisSession) {
647+
// Found the specific session for this token
662648

663-
if (manuallyTerminated) {
664-
// User was explicitly logged out → BLOCK
649+
if (thisSession.terminatedManually === true) {
650+
// This specific session was manually terminated → BLOCK
665651
strapi.log.info(
666-
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... was manually logged out`
652+
`[magic-sessionmanager] [JWT-BLOCKED] Session was manually terminated (user: ${userDocId.substring(0, 8)}...)`
667653
);
668654
return null;
669655
}
670656

671-
// Session was deactivated by timeout → REACTIVATE most recent one
672-
const sessionToReactivate = inactiveSessions[0];
657+
if (thisSession.isActive) {
658+
// Session is active → allow
659+
return decoded;
660+
}
661+
662+
// Session is inactive but NOT manually terminated → reactivate
673663
await strapi.documents(SESSION_UID).update({
674-
documentId: sessionToReactivate.documentId,
664+
documentId: thisSession.documentId,
675665
data: {
676666
isActive: true,
677667
lastActive: new Date(),
@@ -683,7 +673,42 @@ async function registerSessionAwareAuthStrategy(strapi, log) {
683673
return decoded;
684674
}
685675

686-
// No sessions exist at all - session was never created (bug/race condition)
676+
// No session found for this specific token - check if user has ANY sessions
677+
// This handles tokens issued before session manager was installed
678+
const anyActiveSessions = await strapi.documents(SESSION_UID).findMany({
679+
filters: {
680+
user: { documentId: userDocId },
681+
isActive: true,
682+
},
683+
limit: 1,
684+
});
685+
686+
if (anyActiveSessions && anyActiveSessions.length > 0) {
687+
// User has other active sessions - allow this token (backward compatibility)
688+
strapi.log.debug(
689+
`[magic-sessionmanager] [JWT] No session for token but user has other active sessions (allowing)`
690+
);
691+
return decoded;
692+
}
693+
694+
// Check for any manually terminated sessions
695+
const terminatedSessions = await strapi.documents(SESSION_UID).findMany({
696+
filters: {
697+
user: { documentId: userDocId },
698+
terminatedManually: true,
699+
},
700+
limit: 1,
701+
});
702+
703+
if (terminatedSessions && terminatedSessions.length > 0) {
704+
// User was logged out (all sessions terminated) → BLOCK
705+
strapi.log.info(
706+
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... has terminated sessions`
707+
);
708+
return null;
709+
}
710+
711+
// No sessions at all - session was never created
687712
if (strictMode) {
688713
strapi.log.info(
689714
`[magic-sessionmanager] [JWT-BLOCKED] No sessions exist for user ${userDocId.substring(0, 8)}... (strictMode)`

0 commit comments

Comments
 (0)