Hawk authentication is designed to work without transport security. When TLS is used, replay protection is not much of an issue but it is an interesting thing to see how replays are handled in Hawk.
Similar to Hawk, HTTP digest authentication is also designed to work without TLS. Digest authentication uses a server-generated nonce and a nonce counter to defend against replays. How the server generates the nonce is left to the implementation. A server can store the nonce and look up a store to see if the nonce it received is a nonce it generated and take the corresponding timestamp (if stored together) and determine if the nonce is fresh or not. If the nonce is stale, a new nonce is generated and sent back with a 401.
In Hawk, replays are handled by nonce as well as a timestamp check. The major difference compared to the digest authentication is the nonce are generated by the client and not the server. In the case of digest, the initial request must always be rejected by the server with a 401 so that the server-generated nonce can be sent as part of this response in the WWW-Authenticate header. Hawk however uses the client-generated nonce and this initial request failure is not needed for hawk to work. Also, nonce does not get reused in case of Hawk. The CreateClientAuthorizationInternalAsync method in the HawkClient class in Thinktecture.IdentityModel.45 generates a new nonce every time it gets called to create the Authorization header payload. Also, in the server side, there is no need to store and check the nonce. All it takes to convince the server that the request is authentic is sending the right MAC, computed using the nonce in the request.
Now, the freshness part. The timestamp field in the request is part of the MAC and hence it must match the timestamp the client has put in the request. The server can use this timestamp field to ensure a request is not replayed. By default, the Hawk implementation in Thinktecture.IdentityModel.45 uses a time window of 60 seconds. This is taken from the ClockSkewSeconds property of the Options class. This basically means the server clock and the client clock can have a skew of 120 seconds max (+60 and -60).
Hawk uses an interesting mechanism to ensure the clock skews are within the reasonable limits. When the server must fail a request on account of stale timestamp (MAC computed matches with the one in the request but timestamp is outside of the allowable skew), the server sends the timestamp (ts) as per the server clock along with a MAC (tsm) computed using the client credentials, in the WWW-Authenticate response header like so.
HTTP/1.1 401 Unauthorized WWW-Authenticate: Hawk ts="1353832234", tsm="6G8r5JiE+NLoym+WwjeHzjDNCUtLNIxmo1vpMofpLAE="
Now, the client can verify the authenticity of timestamp using tsm, calculate the skew of the server clock from it’s own clock and apply this offset on all future requests. The client is not expected to and in fact MUST NOT adjust the clock based on ts from the server, since this opens up the possibilities of client clock getting poisoned.
In Thinktecture.IdentityModel.45 implementation, HawkClient stores the offset and applies it on all the subsequent requests. Of course, this feature is optional and is driven by the EnableAutoCompensationForClockSkew property in the ClientOptions class.