Leaving aside projects where the use of this standard is prescribed, e.g. due to integration or compliance requirements…
Compared to other authentication mechanisms that work at the HTTP layer, signatures offer a number of benefits:
- Credentials are not transmitted on the wire, unlike Basic or Bearer auth; this is generally a good thing regardless of whether the channel is encrypted
- It does not require a challenge/response roundtrip and keeping state on the server, unlike Digest auth
- It verifies the integrity of selected parts of the HTTP request, preventing modification of those parts by intermediaries
- Support for non-repudiation (except when using HMAC)
- Private key never leaves the client, so it is less likely to leak compared to symmetrical credentials that need to be defined in client and server (again, does not apply to HMAC)
Compared to authentication at the TLS layer, e.g. a client certificate:
- Does not impose requirements on TLS proxies (e.g. cloud load balancers)
- Works with browser-based clients
Of course you could implement the whole thing in a higher layer, using HTTP only as a dumb pipe. I generally try to avoid pushing functionality up the stack, preferring to leverage the services of lower layers (in this case HTTP) and handling only my business logic in the application layer. This allows me to delegate things like authentication and authorisation (e.g. to Plugs or API gateways) without impacting my APIs.
As for headers being manipulated between client and server, this hasn’t been an issue for me: headers that are likely to be modified often do not require integrity protection. In earlier versions of the spec the Date header was included in the signature, to limit the signature validity, and this could be problematic (also for AJAX clients), but the latest drafts use the created/expires parameters of the signature header instead.