At Mozilla, we recently had to implement the Hawk authentication scheme for a number of projects, and we came up creating two libraries to ease integration into Pyramid and Node.js apps.
But maybe you don’t know Hawk?
Hawk is a relatively new technology, crafted by one of the original OAuth specification authors, that intends to replace the 2-legged OAuth authentication scheme using a simpler approach.
It is an authentication scheme for HTTP, built around HMAC digests of requests and responses.
Every authenticated client request has an Authorization header containing a MAC (Message Authentication Code) and some additional metadata, then each server response to authenticated requests contains a Server-Authorization header thatauthenticates the response, so the client is sure it comes from the right server.
Exchange of the hawk id and hawk key
To sign the requests, a client needs to retrieve a token id and a token key from the server.
The excellent team behind Firefox Accounts put together a scheme to do that, if you are not interested in the details, jump directly to the next section.
When your server application needs to send you the credentials, it will return it inside a specific Hawk-Session-Token header. This token can be derived to split this string in two values (hawk id and hawk key) that you will use to sign your next requests.
In order to get the hawk credentials, you’ll need to:
First, do an HKDF derivation on the given session token. You’ll need to use the following parameters:
key_material = HKDF(hawk_session, "", 'identity.mozilla.com/picl/v1/sessionToken', 32*2)
The identity.mozilla.com/picl/v1/sessionToken is a reference to this way of
deriving the credentials, not an actual URL.
Then, the key material you’ll get out of the HKDF need to be separated into two parts, the first 32 hex caracters are the hawk id, and the next 32 ones are the hawk key.
To showcase APIs in the documentation, we like to use HTTPie, a curl-replacement with a nicer
API, built around the python requests library.
Luckily, HTTPie allows you to plug different authentication schemes for it, so we created a wrapper around mohawk to add hawk support to the requests lib.
Doing hawk requests in your terminal is now as simple as:
$ pip install requests-hawk httpie
$ http GET localhost:5000/registration --auth-type=hawk --auth='id:key'
In addition, it helps crafting requests using the requests library:
Alternatively, if you don’t have the token id and key, you can pass the hawk session token presented earlier and the lib will take care of the derivation for you.
Integrate with python pyramid apps
If you’re writing pyramid applications, you’ll be happy to learn that Ryan Kelly put together a library that makes Hawk work as an Authentication provider for them. I’m shocked how simple it is to use it.
Here is a demo of how we implemented it for Daybed, a form validation and data storage API:
The get_hawk_id function is a function that takes a request and a tokenid and returns a tuple of (token_id, token_key).
How you want to store the tokens and retrieve them is up to you. The default implementation (e.g. if you don’t pass a decode_hawk_id function) decodes the key from the token itself, using a master secret on the server (so you don’t need to store anything).
Integrate with node.js Express apps
We had to implement Hawk authentication for two node.js projects and finally came up factorizing everything in a library for express, named express-hawkauth.
In order to plug it in your application, you’ll need to use it as a middleware:
If you pass the createSession parameter, all non-authenticated requests will create a new hawk session and return it with the response, in the Hawk-Session-Token header.
If you want to only check a valid hawk session exists (without creating a new one), just create a middleware which doesn’t have any createSession parameter defined.
Some reference implementations
As a reference, here is how we’re using the libraries I’m talking about, in case that helps you to integrate with your projects.