
Автентифікація в NestJS: доступ, поновлення токенів і припинення сеансів
- NestJS authentication
- access token
- refresh token
- token rotation
- session revocation
- JWT security
- logout all devices

Автентифікація в NestJS: доступ, поновлення токенів і припинення сеансів
Автентифікація у робочому продукті — це система безпеки з повним життєвим циклом, а не контролер, який лише підписує JWT. Вона повинна обмежувати користь викрадених облікових даних, розрізняти сеанси й пристрої, правильно обробляти одночасні поновлення, припиняти тривалий доступ після виходу або зламу, захищати браузерні сценарії, замінювати ключі, зберігати докази для аудиту та безпечно поводитися за недоступності бази даних чи постачальника ідентифікації.
У практичній системі для власних клієнтів короткочасні й тривалі повноваження слід розділяти. Підписаний токен доступу з малим строком дії підтверджує заявлені відомості для API без звернення до сховища сеансів під час кожного звичайного запиту. Випадковий секрет із високою ентропією дає змогу продовжити один серверний сеанс і замінюється після кожного використання. Остаточним джерелом істини для тривалого доступу залишається база даних, а строк дії токена доступу визначає найбільшу звичайну затримку, з якою відкликання пошириться на кінцеві точки без стану.
Ця модель підходить не всім. Зрілий постачальник OpenID Connect може бути безпечнішим за самостійну підтримку паролів і відновлення доступу. Для ризикованих операцій можуть знадобитися недавня повторна автентифікація, MFA, окремий дозвіл на конкретну операцію або перевірка чинного сеансу. Мобільні, браузерні, машинні та партнерські клієнти мають різні можливості зберігання секретів і прив’язування їх до відправника. Починайте з моделі загроз: викрадення облікових даних, XSS, CSRF, витік бази даних, повторне використання токена, виявлення наявності облікового запису, фіксація сеансу, внутрішній зловмисник, компрометація ключа та відмова в обслуговуванні.
Перш ніж обирати строки дії токенів, опишіть очікувані результати: які дії треба блокувати негайно, як користувач переглядає і завершує сеанси, що саме відкликає скидання пароля, чи відокремлені ключі API, за яких умов служба підтримки може діяти від імені користувача, які події спричиняють сповіщення та які докази потрібні фахівцям під час інциденту. Наші послуги з розробки на NestJS допомагають пристосувати ці засоби контролю до клієнтів, ризиків, нормативних вимог і можливостей експлуатації конкретного продукту.
Установіть межі довіри до особи й токена
Вхід починається на недовіреній межі системи. Перевіряйте DTO під час виконання, обережно нормалізуйте ідентифікатори, обмежуйте частоту запитів за кількома обґрунтованими ознаками й формуйте відповіді так, щоб вони не розкривали існування облікового запису. Паролі перевіряйте сучасною функцією гешування з налаштованою вартістю обчислень, а потім застосовуйте правила стану облікового запису, підтверджених каналів, MFA, ризику та відновлення. Створюйте сеанс лише після успіху всіх обов’язкових чинників; ідентифікатор попереднього сеансу обов’язково замініть, щоб запобігти його фіксації.
Токен доступу випускайте з явно визначеним алгоритмом підпису та керованим ключем. Перевірка повинна обмежувати алгоритм, ключ і підпис, видавця, одержувача, строк дії, час початку чинності, якщо він зазначений, тип токена й обов’язкові поля; просте декодування нічого не підтверджує. Набір даних усередині має бути мінімальним: суб’єкт, ідентифікатор сеансу або сімейства, ідентифікатор токена, видавець, одержувач, час випуску й завершення дії, а також лише ті відомості про права, яким безпечно залишатися незмінними протягом цього короткого строку. Автентифікація визначає особу, але NestJS-захисники та прикладна логіка все одно повинні дозволити конкретну операцію над конкретним ресурсом.
Власника ключів і порядок їх заміни визначте від початку. Симетричний підпис доречний за єдиної межі між видавцем і перевіряльником; асиметричні ключі спрощують незалежну перевірку та обмежене поширення секретних даних. Закриті й спільні секрети зберігайте у спеціалізованому сховищі, додавайте ідентифікатор ключа, коли це потрібно, і публікуйте тільки призначені для перевірки ключі. Старий і новий ключі приймайте одночасно протягом задокументованого перехідного періоду, а невідомі алгоритми й ключі відхиляйте. Інструкція на випадок термінової компрометації має називати відповідального за заміну, спосіб оновлення всіх перевіряльників, перелік недійсних сеансів або токенів і порядок повідомлення клієнтів.
Керуйте поновленням як серверним сеансом
Тривалий доступ представляйте як серверний сеанс або сімейство токенів. Створіть непрозорий секрет поновлення з криптографічно надійного джерела випадковості, поверніть його клієнту лише один раз, а в базі зберігайте тільки геш із секретним ключем. Тоді витік бази даних не перетворить записи на готові облікові дані. Зберігайте користувача, сімейство, поточний токен, час створення й останнього використання, строк бездіяльності та остаточний строк, посилання на наступника, час і причину відкликання, рівень автентифікації та мінімальні відомості про пристрій. Під час кожної заміни успадковуйте початковий остаточний строк, щоб активність не подовжувала доступ безмежно.
У браузері секрет поновлення зазвичай варто передавати у файлі cookie з належною областю дії та ознаками Secure і HttpOnly: звичайний JavaScript не зможе його прочитати. Значення SameSite обирайте відповідно до справжньої схеми входу й розміщення застосунку; за можливості звужуйте Path і Domain, обов’язково використовуйте HTTPS та захищайте від CSRF кожний запит зі зміною стану, що спирається на cookie. Ознака HttpOnly не знешкоджує XSS, адже сторонній код у сторінці й надалі здатен діяти через браузер. Не розміщуйте токени в адресах або журналах, а для чутливих відповідей установіть доречні правила кешування.
Застосунки для телефонів і настільних систем мають зберігати секрети засобами захисту платформи та враховувати загрози відкритого клієнта. Конфіденційний серверний клієнт може автентифікувати себе, натомість застосунок, що поширюється користувачам, не здатний надійно зберігати спільний секрет. Якщо протокол і клієнт це підтримують, розгляньте прив’язування облікових даних до відправника. Назва пристрою, дані про програму-клієнт, IP-адреса й географічне розташування допомагають користувачеві впізнати активність і корисні для оцінювання ризику, проте це мінливі сигнали, а не доказ особи. Не блокуйте доступ автоматично через звичайні подорожі, мережі операторів, служби приховування адреси або оновлення програм.
CREATE TABLE auth_session (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
family_id UUID NOT NULL,
refresh_token_digest CHAR(64) NOT NULL UNIQUE,
replaced_by_session_id UUID NULL,
created_at TIMESTAMPTZ NOT NULL,
last_used_at TIMESTAMPTZ NOT NULL,
idle_expires_at TIMESTAMPTZ NOT NULL,
absolute_expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ NULL,
revoke_reason VARCHAR(64) NULL,
CONSTRAINT auth_session_replacement_fk
FOREIGN KEY (replaced_by_session_id) REFERENCES auth_session(id)
);
CREATE INDEX auth_session_user_active_idx
ON auth_session (user_id, revoked_at);
CREATE INDEX auth_session_family_idx
ON auth_session (family_id);Замінюйте токени неподільно, а повторне використання вважайте загрозою
Кожні прийняті облікові дані поновлення повинні стати непридатними й породити рівно одного наступника в тому самому сімействі. Пошук гешу, перевірку строків і відкликання, анулювання старого токена, створення нового та зв’язування обох записів виконуйте в одній транзакції бази даних із блокуванням рядка або умовним записом. Інакше два одночасні запити можуть прийняти той самий секрет і створити дві активні гілки. Установіть обмеження унікальності відповідно до моделі, а в клієнті об’єднуйте паралельні спроби поновлення, щоб кожний невдалий запит до API не запускав власну заміну.
Повторна поява вже заміненого токена може означати компрометацію. RFC 9700 описує послідовну заміну як спосіб виявлення повторного використання, оскільки сервер авторизації зберігає зв’язок між попереднім і новим токенами. Сервер не здатний надійно визначити, хто скористався секретом першим — законний клієнт чи нападник. Відкличте чинне сімейство, відхиліть наступні поновлення, запишіть подію безпеки без самого секрету та вимагайте нового входу. Користувача або команду безпеки сповіщайте відповідно до ризику й правил продукту.
Ненадійна мережа створює неоднозначність: сервер міг завершити заміну, а відповідь — загубитися. Вузький і ретельно проаналізований пільговий механізм іноді покращує зручність, але вільне приймання старого токена знищує захист від повторного використання. Перш ніж дозволяти виняток, опишіть автомат станів та його незмінні правила: найбільшу кількість використань, часовий проміжок, доказ того самого клієнта, відновлення відповіді й реакцію на другу появу. Відкликання має зберігатися навіть за повернення помилки: якщо виняток усередині транзакції скасовує анулювання сімейства, це непомітна, але серйозна вада реалізації.
async rotate(presented: string): Promise<TokenPair> {
const digest = this.tokenDigest(presented);
const outcome = await this.dataSource.transaction(async (manager) => {
const current = await manager.findOne(AuthSession, {
where: { refreshTokenDigest: digest },
lock: { mode: 'pessimistic_write' },
});
if (!current || this.isExpired(current)) {
throw new UnauthorizedException();
}
if (current.replacedBySessionId) {
await this.revokeFamily(manager, current.familyId, 'refresh_reuse');
return { kind: 'reused' } as const;
}
if (current.revokedAt) throw new UnauthorizedException();
const rawNext = randomBytes(32).toString('base64url');
const next = manager.create(AuthSession, {
id: randomUUID(),
userId: current.userId,
familyId: current.familyId,
refreshTokenDigest: this.tokenDigest(rawNext),
createdAt: new Date(),
lastUsedAt: new Date(),
idleExpiresAt: this.nextIdleExpiry(),
absoluteExpiresAt: current.absoluteExpiresAt,
});
await manager.save(next);
current.replacedBySessionId = next.id;
current.lastUsedAt = new Date();
await manager.save(current);
return { kind: 'rotated', userId: current.userId, next, rawNext } as const;
});
// Throw after commit so replay-triggered family revocation survives.
if (outcome.kind === 'reused') throw new UnauthorizedException();
return this.issuePair(outcome.userId, outcome.next.id, outcome.rawNext);
}Чітко визначте наслідки відкликання
Різні операції слід визначити окремо. «Вийти на цьому пристрої» означає відкликати поточний сеанс або сімейство та видалити браузерний cookie з тими самими Path, Domain, Secure і SameSite та належним строком завершення. Операція має бути ідемпотентною: повторний запит не відновлює сеанс і не розкриває його стан. «Вийти на всіх пристроях» відкликає всі відповідні сеанси облікового запису в межах однієї контрольованої операції. Дайте користувачеві змогу переглядати недавні сеанси й завершувати обраний, але не вважайте показані відомості про пристрій доказом особи.
Скидання пароля, підтверджене захоплення облікового запису, його вимкнення, вилучення чинника автентифікації, дія адміністратора або ризикована заміна облікових даних можуть вимагати ширшого відкликання та недавньої повторної автентифікації. Окремо вирішіть долю ключів API, делегованих дозволів, довірених пристроїв, кодів відновлення та партнерських сеансів. Очищення сховища на клієнті не є відкликанням: рекомендації OWASP вимагають анулювання на сервері. Для чутливих сторінок передбачте заголовки кешування й очищення браузерних даних, але не підміняйте цим рішення сервера.
Самодостатній JWT доступу може залишатися чинним до завершення строку. Якщо бізнесу потрібне негайне блокування, на чутливих межах перевіряйте поточний стан сеансу або версію безпеки користувача чи ведіть короткочасний кеш відкликань. Такий вибір навмисно додає стан, затримку й залежність від доступності, тому заздалегідь опишіть поведінку за збою: дозволяти чи забороняти запит. Інший варіант — ще коротший строк токена доступу та додаткова перевірка для важливих дій. Рішення має спиратися на ціну втрат і модель загроз, а не на запозичену «універсальну» тривалість.
Перевіряйте ворожі та одночасні сценарії
Перевіряйте токени як ворожі вхідні дані. Охопіть неправильну будову, надмірні заголовки, хибні підписи, спроби підміни алгоритму, невідомі ідентифікатори ключів, неправильного видавця чи одержувача, прострочений і ще не чинний час, відсутність обов’язкових полів, хибний тип токена, відкликані сеанси, завершення строку бездіяльності й остаточного строку, вимкнення користувача та спробу доступу до чужої організації чи запису. Переконайтеся, що засоби декодування ніде не підміняють автентифікацію, а HTTP, GraphQL, WebSocket та обмін повідомленнями, якщо він є, застосовують однакові правила.
Окремо перевірте одночасність і часткові відмови. Надішліть ті самі облікові дані поновлення паралельно й доведіть, що чинним залишається лише один наступник. Повторіть уже замінений токен і переконайтеся, що відкликання сімейства не скасовується. Зімітуйте втрату відповіді про заміну, повторний вихід, змагання виходу з поновленням, заміну ключів під навантаженням, недоступність бази сеансів, вичерпання обмеження запитів і повтор після закінчення часу очікування. Перевірте видалення cookie, CORS, відхилення CSRF, кешування, допустиме розходження годинників і доступні для сприйняття повідомлення клієнта.
Телеметрія автентифікації повинна поважати приватність. Вимірюйте невдалі входи, результати поновлення, виявлене повторне використання, відкликання, невдачі MFA, створення сеансів, помилки перевірки ключів і затримку, але не записуйте паролі, сирі токени, посилання скидання, секрети чи зайві персональні дані. Захистіть аудиторські записи від підміни та обмежте доступ до них. Кожне сповіщення потребує відповідального й інструкції реагування; слабкі ознаки, як-от зміна IP-адреси або програми-клієнта, мають допомагати розслідуванню, а не автоматично доводити злам.
Проведіть навчання для різних компрометацій: витік ключа підпису, розкриття бази токенів поновлення, шкідлива залежність, викрадений пристрій, масовий перебір викрадених паролів і збій постачальника ідентифікації. План реагування має визначати локалізацію загрози, заміну ключів і припинення сеансів, повідомлення клієнтів, збереження доказів, відновлення та зміни після інциденту. Автентифікація готова до робочого середовища лише тоді, коли її відмови спроєктовані й перевірені так само ретельно, як успішний вхід.
Перевірка автентифікації перед запуском
- Перевірений доступ: токени доступу мають короткий і обґрунтований строк; до надання дозволу перевіряються алгоритм, ключ, підпис, видавець, одержувач, час, тип та обов’язкові поля.
- Захищене поновлення: облікові дані поновлення є секретами з високою ентропією, захищаються під час передавання і зберігання на клієнті, ніколи не потрапляють до адрес або журналів, а в базі існують лише як геші із секретним ключем.
- Неподільна заміна: одна транзакція поглинає поданий токен, створює єдиного наступника, зберігає остаточний строк і історію сімейства, щоб повторне використання призводило до відкликання чинної гілки.
- Однозначне відкликання: вихід на одному чи всіх пристроях, скидання пароля, захоплення або вимкнення облікового запису, дія адміністратора, ключі API та затримка недійсності JWT доступу мають задокументовані наслідки.
- Захищена межа браузера: атрибути cookie, довірені джерела, CORS, захист від CSRF, CSP, правила кешування, протидія XSS та очищення після виходу відповідають справжній схемі розгортання, а не початковим місцевим налаштуванням.
- Керована безпека: заміна ключів, телеметрія без секретів, обмеження частоти, захист аудиту, навчання з відновлення, відповідальні за сповіщення, реагування на компрометацію та оновлення залежностей є перевіреними обов’язками.
Чи варто робити токен поновлення у форматі JWT?
Який строк дії обрати для доступу й поновлення?
Чи усуває cookie з HttpOnly ризики XSS і CSRF?
Чи може вихід негайно зробити JWT доступу недійсним?
Опишіть клієнтів, способи встановлення особи, зберігання токенів, модель сеансів, чутливі операції, нормативні обмеження та сценарії інцидентів. Ми знайдемо конкретні прогалини й визначимо співмірні правила заміни та відкликання, захисту браузера, телеметрії і відновлення.
Наші дослідження
Дослідження та розробка рішень на основі штучного інтелекту для оптимізації бізнес-процесів і підвищення ефективності прийняття рішень.
Аналіз моделей машинного навчання для прогнозної аналітики у фінансовій сфері, електронній комерції та SaaS-платформах.
Дослідження технологій обробки природної мови та комп'ютерного зору для посилення автоматизації, персоналізації та підтримки клієнтів.


