Create and retain the grant key
Generate an ES256 key on the P-256 curve with a standards-based JavaScript Object Signing and Encryption (JOSE) or Web Cryptography application programming interface (API). Keep the private key inside the client’s secure storage and calculate the RFC 7638 thumbprint from its public JSON Web Key (JWK). Authorization-code clients send that thumbprint asdpop_jkt. Device clients establish the binding when they first exchange the device code. Refresh requests must use the original key, so losing it requires authorization again.
Never send the private JWK to Perflo. Do not write the private key, DPoP proof, authorization code, access token, or refresh token to logs or fixtures.
Build a proof for the target endpoint
Each DPoP proof is a signed JSON Web Token (JWT) with an embedded public JWK. Build it for the exact discovered endpoint address and HTTP method. The proof header contains:typset todpop+jwtalgset toES256jwkcontaining only the public key
jtiwith a unique value for this proofhtmwith the uppercase HTTP methodhtuwith the normalized target URI, excluding query and fragmentiatwith the current issue timenoncewhen Perflo requires the current server nonceathwith the access-token hash for a protected API request
jti for every proof. Perflo rejects stale proofs and reused identifiers. Authorization-server and protected-resource nonces are separate, so store them by endpoint role and replace a nonce whenever that endpoint returns a new one.
Send the proof at the token endpoint
Send the proof in theDPoP header when exchanging an authorization code or device code and when refreshing a grant. Confidential clients also authenticate with private_key_jwt; public clients use token endpoint authentication none.
If Perflo returns a DPoP-Nonce header and a standard nonce challenge, create a new proof with that nonce before retrying. Never reuse the challenged proof because its jti is no longer fresh.
The token response uses token_type=DPoP. Treat every returned token as opaque, even when an access token has a JWT shape.
Send a protected API request
An operation protected byPerfloOAuth in the OpenAPI document requires both headers:
htm and htu must match that request, and its ath must bind the exact access token.
Do not use Authorization: Bearer, cookies, query parameters, or request bodies as API credentials. Cross-origin resource sharing does not replace token or DPoP validation.
Keep bindings stable through refresh
A refresh token inherits the grant’s environment resource and DPoP key. Omitresource to retain the original value, or send that same single value.
A refresh request can keep or narrow the granted scope set. It cannot change the DPoP key, add a scope, switch resources, or extend a grant beyond its registered and consented ceiling.
See Choose an OAuth client profile for grant requirements and Call Perflo from a browser for browser-origin rules.