Делегированный доступ и on-behalf-of (OBO) токены в архитектуре современных приложений используются для передачи прав пользователя через цепочку сервисов без утраты контекста исходной авторизации. В экосистеме JWT и спецификаций JOSE эта модель реализуется через криптографически защищённые токены, позволяющие сервисам действовать от имени пользователя, сохраняя при этом контроль над правами доступа и границами доверия.
Делегированный доступ предполагает, что один сервис получает право выполнять действия от имени пользователя в другом сервисе. При этом ключевой принцип заключается в том, что исходные пользовательские полномочия не заменяются сервисными, а аккуратно «протягиваются» через цепочку вызовов.
Типичный сценарий:
Без механизма делегирования каждый этап потребовал бы повторной аутентификации или передачи слишком широких привилегий. OBO-токены решают эту проблему, сохраняя контекст пользователя.
On-behalf-of токен — это разновидность access token, который содержит информацию о том, что запрос выполняется не напрямую пользователем, а сервисом от его имени.
Структурно OBO токен обычно включает:
act или
azp)Пример логики:
User -> Service A -> Service B
|
-> OBO token (User context preserved)
В отличие от обычного access token, OBO токен фиксирует факт промежуточного сервиса.
Библиотека Jose в JavaScript реализует спецификации JOSE:
Основная задача JOSE — обеспечить:
В контексте OBO токенов наиболее важен JWS, так как именно подпись гарантирует, что делегирование не было подделано.
Создание подписанного токена:
import { SignJWT } from 'jose'
const secret = new TextEncoder().encode('super-secret-key')
const token = await new SignJWT({
sub: 'user_123',
scope: 'read:messages',
act: {
sub: 'service_A'
}
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('10m')
.setAudience('service_B')
.sign(secret)
Здесь ключевой момент — claim act, который отражает
актор (сервис, действующий от имени пользователя). Это один из
стандартных способов выражения OBO-цепочки.
В сервисе-получателе токен необходимо проверить:
import { jwtVerify } from 'jose'
const secret = new TextEncoder().encode('super-secret-key')
const { payload } = await jwtVerify(token, secret, {
audience: 'service_B'
})
console.log(payload.sub) // user_123
console.log(payload.act) // { sub: 'service_A' }
Проверка аудитории критически важна: она предотвращает использование токена вне предназначенного сервиса.
В реальных системах OBO токен не создаётся произвольно. Он получается через процесс обмена токенов (token exchange), описанный в RFC 8693.
Схема:
Пример логики запроса обмена:
POST /token
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=USER_TOKEN
requested_token_type=access_token
audience=service_B
Результат:
Библиотека jose не выполняет token exchange сама по себе, но используется для:
Пример цепочки:
const userTokenPayload = await jwtVerify(userToken, publicKey)
const oboToken = await new SignJWT({
sub: userTokenPayload.payload.sub,
scope: 'read:messages',
act: {
sub: 'service_A'
}
})
.setProtectedHeader({ alg: 'RS256' })
.setIssuedAt()
.setExpirationTime('5m')
.setAudience('service_B')
.sign(privateKey)
Ключевое отличие — новый токен подписывается ключом текущего сервиса,
но сохраняет пользовательский sub.
В сложных микросервисных системах OBO может формировать цепочку:
User → Service A → Service B → Service C
Каждый уровень добавляет свой контекст:
"act": {
"sub": "service_B",
"previous_act": {
"sub": "service_A"
}
}
Хотя стандарт не требует вложенных акторов, подобная модель используется в расширенных архитектурах.
Использование делегированного доступа требует строгого соблюдения правил:
Каждый токен должен быть привязан к конкретному сервису:
Время жизни OBO токенов обычно ограничено несколькими минутами:
Каждый последующий сервис должен получать только необходимые права:
Сервис должен анализировать:
В системах, использующих JOSE и OBO, часто встречаются следующие проблемы:
Сервисы заменяют sub на свой идентификатор, что делает
невозможным аудит действий пользователя.
Это приводит к отсутствию сегментации доступа и нарушает модель доверия.
Игнорирование aud позволяет использовать токен вне его
назначения.
Передача полного набора прав через всю цепочку увеличивает поверхность атаки.
Jose в Node.js выступает фундаментальным инструментом для:
Особенно важна возможность работы с асимметричными ключами:
Это обеспечивает масштабируемую модель доверия между независимыми компонентами системы.
В распределённых системах OBO токены часто комбинируются с:
Типичный поток:
Такая модель позволяет строить систему, где каждый компонент независим, но при этом сохраняет общий контекст безопасности.
Помимо sub и act, в OBO токенах часто
используются:
azp — authorized party (первичный клиент)scp — scopesiat, exp — временные ограниченияiss — issueraud — аудиторияКомбинация этих полей позволяет точно описать происхождение запроса и уровень доверия.
Особенно важным становится поле iss, которое позволяет
определить, какой сервис инициировал делегирование, что критично при
анализе цепочек запросов в распределённых системах.
В основе jose лежит принцип:
Это означает, что OBO токен безопасен только при строгом контроле ключей и алгоритмов подписи, а также корректной реализации проверки claims на каждом уровне системы