Step-Up MFA верификация
Используйте MFA Verification API от VoxKey для подтверждения чувствительных действий -- переводов денег, смены пароля, административных операций -- проверяя пользователей через их зарегистрированные MFA факторы. Ваше приложение делегирует весь MFA-поток VoxKey: не нужно самим реализовывать валидацию TOTP, rate limiting или защиту от brute-force.
Зачем нужен step-up MFA?
MFA при логине подтверждает кто пользователь. Step-up MFA подтверждает что пользователь всё ещё здесь в самый важный момент -- удаление аккаунта, перевод денег, смена пароля или создание API-ключа.
Без step-up верификации скомпрометированная сессия (украденный токен, незаблокированный ноутбук) позволяет выполнить любое действие, на которое пользователь авторизован.
Быстрый старт: TOTP верификация
Простейшая интеграция требует три API-вызова: получить список факторов, создать challenge, затем проверить код.
const REALM = 'your-realm-uuid';
const BASE = `https://app.voxkey.io/api/v1/${REALM}/mfa`;
// 1. Получаем зарегистрированные факторы пользователя
const factors = await fetch(`${BASE}/factors`, {
headers: { Authorization: `Bearer ${accessToken}` },
}).then(r => r.json());
const totp = factors.enrolled.find(f => f.type === 'totp');
if (!totp) throw new Error('У пользователя не зарегистрирован TOTP фактор');
// 2. Создаём challenge
const challenge = await fetch(`${BASE}/challenges`, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
factor_type: 'totp',
purpose: 'transaction.approve',
}),
}).then(r => r.json());
// 3. Проверяем код пользователя
const result = await fetch(`${BASE}/challenges/${challenge.challenge_id}/verify`, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ code: userEnteredCode }),
}).then(r => r.json());
if (result.verified) {
// Выполняем чувствительное действие
// result.step_up_token доступен если был установлен issue_step_up_token
}
Сценарии интеграции
Традиционное веб-приложение (серверное)
Ваш бэкенд вызывает VoxKey напрямую. Результат верификации является доверенным, поскольку не покидает сервер.
Браузер --> Ваш бэкенд --> VoxKey MFA API (challenge + verify) --> verified: true --> выполнение действия
- Пользователь нажимает "Подтвердить перевод"
- Бэкенд создаёт challenge для фактора пользователя
- Пользователь вводит код в вашем интерфейсе
- Бэкенд отправляет код на endpoint верификации
- Если
verified === true, действие выполняется немедленно
Step-up токен не нужен -- сервер уже имеет доверенный результат.
Single-Page Application (SPA)
SPA вызывает VoxKey (через прокси на бэкенде или напрямую, если access token имеет нужный scope). После верификации API возвращает step-up токен -- короткоживущий подписанный JWT, который ваш бэкенд валидирует перед выполнением действия.
Браузер --> VoxKey MFA API (challenge + verify) --> step_up_token
Браузер --> Ваш бэкенд (действие + заголовок X-Step-Up-Token)
Ваш бэкенд --> валидация JWT через JWKS --> выполнение действия
Запросите токен, установив issue_step_up_token: true при создании challenge. См. Step-Up Token для деталей валидации.
Микросервисы
Сервис A верифицирует пользователя и передаёт step_up_token сервису B, который выполняет действие. Сервис B валидирует токен независимо через JWKS -- callback к VoxKey не требуется.
SPA --> API Gateway --> VoxKey MFA API --> step_up_token
--> API Gateway --> Payment Service (валидация токена через JWKS) --> выполнение
Токен является самодостаточным (подписанный JWT), поэтому downstream-сервисам не нужно повторно обращаться к VoxKey для его проверки.
Конвенции purpose
Поле purpose -- обязательная строка, которая привязывает challenge к конкретному действию. Используйте точечные namespace'ы для организации.
| Namespace | Примеры | Описание |
|---|---|---|
reauth | reauth | Общее "подтвердите, что это вы" перед чувствительной страницей |
account.* | account.delete, account.email_change | Действия с жизненным циклом аккаунта |
password.* | password.change, password.reset | Операции с паролем |
billing.* | billing.payment_method, billing.subscription | Финансовые и биллинговые операции |
transaction.* | transaction.approve, transaction.withdraw | Подтверждение транзакций |
admin.* | admin.role_change, admin.config_change | Административные действия |
Purpose валидируется по паттерну: /^[a-z][a-z0-9_.]{2,50}$/
Step-up proof для account.delete нельзя переиспользовать для billing.subscription. Ваш бэкенд всегда должен проверять, что claim purpose в токене соответствует выполняемому действию.
Что происходит при ошибке
- Неверный код: Счётчик попыток challenge увеличивается. После 5 неудачных попыток challenge блокируется и возвращает
410 Gone. - Истёкший challenge: У challenge есть TTL (5 минут для TOTP/WebAuthn, 10 минут для email/SMS). После истечения создайте новый challenge.
- Rate limit: Более 5 созданий challenge в минуту на пользователя возвращает
429 Too Many Requests. Отступите и повторите попытку.
Следующие шаги
- Справочник MFA API -- полный справочник endpoints со всеми параметрами и ответами
- Step-Up Token -- структура токена и валидация для SPA и микросервисов
- Типы MFA факторов -- сравнение поддерживаемых факторов с rate limits и TTL