DPoP
DPoP (Demonstrating Proof-of-Possession, RFC 9449) — механизм привязки access token к криптографическому ключу клиента. Украденный токен не работает без приватного ключа. Замена/дополнение к bearer-модели.
Проблема Bearer
OAuth 2.0 access token — bearer: кто держит, тот и юзает. Украл через XSS/malware → сервер не отличит легитимного клиента от вора.
Как DPoP решает
- Клиент генерит эфемерную ключевую пару (ES256/RS256/EdDSA).
- При запросе токена — шлёт
DPoPheader с JWS-подписью запроса и публичным ключом (jwk). - AS привязывает access_token к хешу публичного ключа (
cnf.jktclaim). - Клиент шлёт токен + новый
DPoP-JWS на каждый запрос к RS. - RS проверяет: подпись DPoP + jkt в токене совпадает с jkt в DPoP.
DPoP-JWS header
{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": { "kty":"EC", "crv":"P-256", "x":"...", "y":"..." }
}
DPoP-JWS payload
{
"jti": "unique-id",
"htm": "POST", // HTTP method
"htu": "https://api.example.com/token",
"iat": 1700000000,
"ath": "hash_of_access_token" // при запросе к RS
}
HTTP-запрос
GET /api/resource HTTP/1.1
Host: api.example.com
Authorization: DPoP eyJhbGciOiJFUzI1NiIsInR5cCI6Impq...
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIs...
Плюсы
- Украл токен без приватного ключа → бесполезно
- Не требует mTLS-инфраструктуры (клиентских сертификатов)
- Работает для SPA (JWK в IndexedDB / non-extractable CryptoKey)
Против кого не спасёт
Если malware имеет доступ к приватному ключу (extractable в JS) — украдёт и его. Мит: non-extractable CryptoKey (SubtleCrypto).
Adopter-ы
- Solid Project (Tim Berners-Lee)
- OpenBanking (частично)
- Некоторые Auth0/Okta режимы
Альтернатива
mTLS-bound tokens (RFC 8705) — привязка к клиентскому сертификату. Для B2B.