JAR (JWT Secured Authorization Request) представляет собой механизм передачи параметров авторизационного запроса в виде подписанного JWT, что обеспечивает целостность, подлинность и защиту от подмены данных при взаимодействии клиента с авторизационным сервером в протоколах OAuth 2.0 и OpenID Connect.
Основная идея заключается в том, что вместо передачи набора
query-параметров в URL или форме запроса, формируется JWT-объект,
содержащий все параметры авторизации. Этот JWT подписывается
криптографическим ключом клиента и передается в авторизационный сервер
либо напрямую, либо через ссылку request_uri.
JAR использует стандарт JWS (JSON Web Signature), определённый в JOSE. Внутреннее содержимое токена включает стандартные OAuth-параметры:
client_id — идентификатор клиентаredirect_uri — URI возврата после авторизацииresponse_type — тип ответа (например,
code)scope — запрашиваемые разрешенияstate — значение для защиты от CSRFnonce — защита от replay-атак (в OpenID Connect)JWT формируется в виде:
header.payload.signature
Где:
alg,
kid)Библиотека jose в JavaScript предоставляет инструменты для создания и проверки JWS, JWE и JWT. Для JAR используется именно JWS-подпись.
Создание подписанного авторизационного запроса:
import { SignJWT } from 'jose'
import { createPrivateKey } from 'crypto'
const privateKey = createPrivateKey(`
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
`)
const payload = {
client_id: 'client_123',
redirect_uri: 'https://client.example.com/callback',
response_type: 'code',
scope: 'openid profile email',
state: 'af0ifjsldkj',
nonce: 'n-0S6_WzA2Mj'
}
const jar = await new SignJWT(payload)
.setProtectedHeader({ alg: 'RS256', typ: 'JWT' })
.setIssuedAt()
.setExpirationTime('5m')
.sign(privateKey)
Полученный токен передаётся как параметр request или
используется для формирования request_uri.
В ряде реализаций авторизационный сервер не принимает сам JWT напрямую, а требует ссылку на ресурс:
https://server.example.com/auth?request_uri=https://client.example.com/request.jwt
В этом случае JAR предварительно размещается на защищённом сервере клиента, откуда он загружается сервером авторизации.
Авторизационный сервер выполняет валидацию подписи и содержимого JWT:
import { jwtVerify } from 'jose'
import { createPublicKey } from 'crypto'
const publicKey = createPublicKey(`
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
`)
const { payload, protectedHeader } = await jwtVerify(token, publicKey, {
algorithms: ['RS256']
})
После проверки извлекаются параметры запроса и используются как обычный OAuth-запрос.
JAR часто применяется совместно с механизмом PAR. В этом случае:
/parrequest_urirequest_uriТакой подход исключает передачу чувствительных параметров через браузерный URL.
JAR опирается на свойства JWS:
Использование асимметричной криптографии является предпочтительным, так как позволяет серверу авторизации проверять подпись без доступа к приватному ключу клиента.
Заголовок JWS может включать дополнительные параметры:
.setProtectedHeader({
alg: 'RS256',
typ: 'JWT',
kid: 'key-1'
})
Поле kid используется для выбора нужного публичного
ключа при валидации на сервере.
Помимо криптографической проверки, выполняется семантическая валидация:
redirect_uri зарегистрированным значениям
клиентаclient_idexpscope на допустимостьnonce и state на
уникальностьПри передаче параметров авторизации через URL возникают следующие риски:
JAR устраняет эти проблемы за счёт криптографической фиксации состояния запроса.
JAR поддерживается в расширениях:
В таких системах JAR часто является обязательным требованием, особенно при работе с финансовыми данными.
Часто встречающиеся проблемы:
aud и issredirect_uri при валидацииБиблиотека jose предоставляет низкоуровневый контроль над процессом формирования JWS, что требует явного управления:
Это делает реализацию JAR гибкой, но требующей строгого соблюдения спецификации JOSE и OAuth 2.0.