Expand description
Device keys and DPoP proofs (RFC 9449, R18).
§Design
Each device has one P-256 key. The private part stays on the device, in the OS keyring. Each request carries a proof: a short JWT that the key signs (ES256). The proof names the method and the URL of the request, and the hash of the access token. So a copied token or a copied proof is of no use without the key.
Authorization: DPoP <access token>
DPoP: <header>.<payload>.<signature>
header {"typ":"dpop+jwt","alg":"ES256","jwk":{public key}}
payload {"jti","htm","htu","iat","ath"}The server binds each sign-in to the thumbprint of the key (RFC 7638). It accepts a token only with a proof from that key.
§Rules for a valid proof
typisdpop+jwt,algisES256, andjwkis a public P-256 key with no private part.- The signature is good for that key.
htmis the method andhtuis the URL of the request, with no query and no fragment.iatis at mostMAX_AGEseconds old, and at mostMAX_SKEWseconds in the future (R86).jtiis not empty. The server refuses ajtithat it saw before.- With an access token,
athis its hash.
§Example
use riff_core::dpop::{Key, verify};
let key = Key::generate();
let url = "https://riff.example.com/v1/who";
let proof = key.proof("POST", url, Some("t-1"), 1_000);
let checked = verify(&proof, "POST", url, Some("t-1"), 1_000).unwrap();
assert_eq!(checked.jkt, key.thumbprint());
// The proof does not work for another token or another URL.
assert!(verify(&proof, "POST", url, Some("t-2"), 1_000).is_err());
assert!(verify(&proof, "POST", "https://riff.example.com/v1/post", Some("t-1"), 1_000).is_err());Structs§
- Dpop
Error - Why a proof is not valid.
- Jwk
- A public P-256 key as a JWK.
- Key
- The private key of a device.
- Proof
- What a valid proof tells the server.
Constants§
- ALG
- The only signing algorithm.
- MAX_AGE
- A proof may be this many seconds old (R86).
- MAX_
SKEW - A proof may be this many seconds in the future, for clock skew (R86).
Functions§
- token_
hash - The
athof an access token: base64url of its SHA-256 hash. - verify
- Checks a proof for one request. See the module docs for the rules.
The caller checks that the
jtiis new.