oidc-client-ts
oidc-client-ts copied to clipboard
Add dpop nonce support
This is a first cut aimed at adding DPoP
nonce support. I initially removed this feature in the original PR and this is a follow up.
This is very experimental and open to change. @pamapa I would really appreciate your thoughts as to how this could be done more cleanly 🙏🏼
The main functionality is supporting Authorization Server Provided Nonces.
According to the spec, if/when an AS requires the use of a nonce and a token request is made without a nonce claim within the DPoP proof JWT, the AS responds with a specific 400 bad request that includes a response header dpop-nonce
which contains the nonce value to be used. The client is then expected to regenerate its DPoP proof again with the included nonce, and then retry the token request.
Upon receiving the nonce, the client is expected to retry its token request using a DPoP proof including the supplied nonce value in the nonce claim of the DPoP proof. An example unencoded JWT payload of such a DPoP proof including a nonce is shown below.
e.g.
HTTP/1.1 400 Bad Request
DPoP-Nonce: eyJ7S_zG.eyJH0-Z.HX4w-7v
{
"error": "use_dpop_nonce",
"error_description":
"Authorization server requires nonce in DPoP proof"
}
[Figure 20](https://datatracker.ietf.org/doc/html/rfc9449#figure-20): [HTTP 400 Response to a Token Request without a Nonce](https://datatracker.ietf.org/doc/html/rfc9449#name-http-400-response-to-a-toke)
Other HTTP headers and JSON fields MAY also be included in the error response, but there MUST NOT be more than one DPoP-Nonce header.
Upon receiving the nonce, the client is expected to retry its token request using a DPoP proof including the supplied nonce value in the nonce claim of the DPoP proof. An example unencoded JWT payload of such a DPoP proof including a nonce is shown below.
{
"jti": "-BwC3ESc6acc2lTc",
"htm": "POST",
"htu": "https://server.example.com/token",
"iat": 1562262616,
"nonce": "eyJ7S_zG.eyJH0-Z.HX4w-7v"
}
In order to accomodate this I have added a new abstraction DPoPState
, which is an object that contains both the CryptoKeyPair and the optional nonce value. I have altered the DPoPStore
interface to accomodate this as the nonce can be used repeatedly for token requests until the AS decides to invalidate.
Which brings me to my next point, the spec is quite open as to how an AS may provide a new nonce.
The authorization server MAY supply the new nonce in the same way that the initial one was supplied: by using a DPoP-Nonce HTTP header in the response. The DPoP-Nonce HTTP header field uses the nonce syntax defined in Section 8.1. Each time this happens, it requires an extra protocol round trip.
A more efficient manner of supplying a new nonce value is also defined by including a DPoP-Nonce HTTP header in the HTTP 200 (OK) response from the previous request. The client MUST use the new nonce value supplied for the next token request and for all subsequent token requests until the authorization server supplies a new nonce.
I attempted to try and add a way to handle a new nonce upon a 200 response but it was going to be messy and potentially involved altering the SigninResponse
class, which didn't feel right. I looked at how IdentityServer issues new nonces and they just re-use the 400 bad request method. I think we should leave this out for the time being.
In regards to supporting Resource Server provided nonces, that is a lot simpler as the client should manage storing and renewing the resource provided nonce as it will be returned on a client initiated fetch request to the RS - it has nothing to do with oidc-client-ts
. For now I have opted to provide a way to supply the nonce as an optional parameter when creating the DPoPProof on the user manager class. We can revisit if we want to offer a way for clients to store the RS provided nonce values and/or provide helpers to manage them, but this interaction falls outside the relationship between the client and the AS.
Checklist
- [ ] This PR makes changes to the public API
- [ ] I have included links for closing relevant issue numbers