feat(auth): access 24ч, jti против гонок ротации, транзакционная ротация, отзыв сессий по sid

This commit is contained in:
2026-09-21 18:13:46 +03:00
parent 2f9d049718
commit c957a70260
8 changed files with 221 additions and 31 deletions

View File

@@ -1,5 +1,6 @@
import type { Request, Response, NextFunction } from 'express';
import { verifyAccessToken, verifyBotServiceToken, verifySuperAdminToken } from '../utils/jwt';
import { isSessionRevoked } from '../utils/sessionRevocation';
import { storage } from '../storage';
import { withTenant, openTenantCtx, openSuperAdminCtx, _tenantCtx } from '../db';
import { eq } from 'drizzle-orm';
@@ -70,6 +71,15 @@ export const authenticateToken = async (
if (decoded.appRole === 'bot' || (typeof payloadType === 'string' && payloadType.startsWith('bot'))) {
return res.status(401).json({ error: 'Токены ботов не принимаются на этом ресурсе' });
}
// Отзыв устройства: сессия из claim sid отозвана → токен недействителен
// (проверка с кэшем ~30 сек, см. utils/sessionRevocation)
if (decoded.sid && await isSessionRevoked(decoded.sid)) {
return res.status(401).json({ error: 'Сессия отозвана' });
}
// sid сессии — для пометки «текущее устройство» в списке сессий
if (decoded.sid) {
(req as any).sessionId = decoded.sid;
}
// Use JWT organizationId to set tenant context for the users table lookup,
// preventing auth failure when FORCE RLS is active on the users table.
const user = await withTenant(decoded.organizationId, () =>