{"id":551,"date":"2015-02-05T08:42:31","date_gmt":"2015-02-05T08:42:31","guid":{"rendered":"http:\/\/blog.mozilla.org\/services\/?p=551"},"modified":"2018-02-14T23:18:09","modified_gmt":"2018-02-14T23:18:09","slug":"whats-hawk-and-how-to-use-it","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/services\/2015\/02\/05\/whats-hawk-and-how-to-use-it\/","title":{"rendered":"What&#8217;s Hawk authentication and how to use it?"},"content":{"rendered":"<p>At Mozilla, we recently had to implement <a class=\"reference external\" href=\"https:\/\/github.com\/hueniverse\/hawk\">the Hawk authentication scheme<\/a> for a number of projects, and we came up creating two libraries to ease integration into <a href=\"http:\/\/www.pylonsproject.org\/\">Pyramid<\/a> and <a href=\"http:\/\/nodejs.org\">Node.js<\/a> apps.<\/p>\n<p>But maybe you don&#8217;t know Hawk?<\/p>\n<p>Hawk is a relatively new technology, crafted by one of the original <a class=\"reference external\" href=\"https:\/\/en.wikipedia.org\/wiki\/OAuth\">OAuth<\/a> specification authors, that intends to replace the 2-legged OAuth authentication scheme using a simpler approach.<\/p>\n<p>It is an authentication scheme for HTTP, built around <a class=\"reference external\" href=\"https:\/\/en.wikipedia.org\/wiki\/Hmac\">HMAC digests<\/a> of requests and responses.<\/p>\n<p>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.<\/p>\n<h2>Exchange of the hawk id and hawk key<\/h2>\n<p>To sign the requests, a client needs to retrieve a token id and a token key from the server.<\/p>\n<p>The excellent team behind <a class=\"reference external\" href=\"http:\/\/accounts.firefox.com\">Firefox Accounts<\/a> put together a scheme to do that, if you are not interested in the details, jump directly to the next section.<\/p>\n<p>When your server application needs to send you the credentials, it will return it inside a specific <cite>Hawk-Session-Token<\/cite> 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.<\/p>\n<p>In order to get the hawk credentials, you&#8217;ll need to:<\/p>\n<p>First, do an <a class=\"reference external\" href=\"http:\/\/en.wikipedia.org\/wiki\/HKDF\">HKDF derivation<\/a> on the given session token. You&#8217;ll need to use the following parameters:<\/p>\n<pre class=\"literal-block\">key_material = HKDF(hawk_session, \"\", 'identity.mozilla.com\/picl\/v1\/sessionToken', 32*2)\r\n<\/pre>\n<p class=\"last\">The <tt class=\"docutils literal\">identity.mozilla.com\/picl\/v1\/sessionToken<\/tt> is a reference to this way of<br \/>\nderiving the credentials, not an actual URL.<\/p>\n<p>Then, the key material you&#8217;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.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/ametaireau\/b27e18c382156a639c0d.js?file=credentials.js\"><\/script><\/p>\n<h2>HTTPie<\/h2>\n<p>To showcase APIs in the documentation, we like to use <a class=\"reference external\" href=\"https:\/\/github.com\/jakubroztocil\/httpie\">HTTPie<\/a>, a curl-replacement with a nicer<br \/>\nAPI, built around <a class=\"reference external\" href=\"http:\/\/python-requests.org\">the python requests library<\/a>.<\/p>\n<p>Luckily, HTTPie allows you to plug different authentication schemes for it, so <a class=\"reference external\" href=\"https:\/\/github.com\/mozilla-services\/requests-hawk\">we created a wrapper<\/a> around <a class=\"reference external\" href=\"https:\/\/github.com\/kumar303\/mohawk\">mohawk<\/a> to add hawk support to the requests lib.<\/p>\n<p>Doing hawk requests in your terminal is now as simple as:<\/p>\n<pre lang=\"bash\">\r\n$ pip install requests-hawk httpie\r\n$ http GET localhost:5000\/registration --auth-type=hawk --auth='id:key'\r\n<\/pre>\n<p>In addition, it helps crafting requests using the requests library:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/ametaireau\/b27e18c382156a639c0d.js?file=requests-hawk.py\"><\/script><\/p>\n<p>Alternatively, if you don&#8217;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.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/ametaireau\/b27e18c382156a639c0d.js?file=requests-hawk-2.py\"><\/script><\/p>\n<h2>Integrate with python pyramid apps<\/h2>\n<p>If you&#8217;re writing pyramid applications, you&#8217;ll be happy to learn that <a class=\"reference external\" href=\"https:\/\/www.rfk.id.au\/blog\/\">Ryan Kelly<\/a> put together a library that makes Hawk work as an Authentication provider for them. I&#8217;m shocked how simple it is to use it.<\/p>\n<p>Here is a demo of how we implemented it for <a href=\"http:\/\/daybed.readthedocs.org\/\">Daybed<\/a>, a form validation and data storage API:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/ametaireau\/b27e18c382156a639c0d.js?file=pyramid-hawk.py\"><\/script><\/p>\n<p>The <cite>get_hawk_id<\/cite> function is a function that takes a request and a tokenid and returns a tuple of <cite>(token_id, token_key)<\/cite>.<\/p>\n<p>How you want to store the tokens and retrieve them is up to you. The default implementation (e.g. if you don&#8217;t pass a <cite>decode_hawk_id<\/cite> function) decodes the key from the token itself, using a master secret on the server (so you don&#8217;t need to store anything).<\/p>\n<h2>Integrate with node.js Express apps<\/h2>\n<p>We had to implement Hawk authentication for two node.js projects and finally came up factorizing everything in a library for express, named <a class=\"reference external\" href=\"https:\/\/github.com\/mozilla-services\/express-hawkauth\">express-hawkauth<\/a>.<\/p>\n<p>In order to plug it in your application, you&#8217;ll need to use it as a middleware:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/ametaireau\/b27e18c382156a639c0d.js?file=express-hawk.js\"><\/script><\/p>\n<p>If you pass the <cite>createSession<\/cite> parameter, all non-authenticated requests will create a new hawk session and return it with the response, in the <cite>Hawk-Session-Token<\/cite> header.<\/p>\n<p>If you want to only check a valid hawk session exists (without creating a new one), just create a middleware which doesn&#8217;t have any <cite>createSession<\/cite> parameter defined.<\/p>\n<h2>Some reference implementations<\/h2>\n<p>As a reference, here is how we&#8217;re using the libraries I&#8217;m talking about, in case that helps you to integrate with your projects.<\/p>\n<ul class=\"simple\">\n<li>The Mozilla Loop server <a class=\"reference external\" href=\"https:\/\/github.com\/mozilla-services\/loop-server\/blob\/master\/loop\/index.js#L70-L133\">uses hawk as authentication once you&#8217;re logged in with a valid BrowserID assertion<\/a> request, to keep a session between client and server;<\/li>\n<li><a class=\"reference external\" href=\"https:\/\/github.com\/spiral-project\/daybed\/commit\/f178b4e43015fa077430798dcd3d0886c7611caf\">We recently added hawk support on the Daybed project<\/a> (that&#8217;s a pyramid \/ cornice) app;<\/li>\n<li>It&#8217;s also interesting to note that <a href=\"http:\/\/blog.mozilla.org\/webdev\/2012\/03\/02\/better-know-a-webdev-kumar-mcmillan-aka-kumar303\/\">Kumar<\/a> put together <a class=\"reference external\" href=\"http:\/\/hawkrest.readthedocs.org\/en\/latest\/\">hawkrest, for the django rest framework<\/a>.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;t know Hawk? Hawk is a &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/services\/2015\/02\/05\/whats-hawk-and-how-to-use-it\/\">Continue reading<\/a><\/p>\n","protected":false},"author":271,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[41994,41993,128,4730,41995,706],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/posts\/551"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/users\/271"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/comments?post=551"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/posts\/551\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/media?parent=551"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/categories?post=551"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/services\/wp-json\/wp\/v2\/tags?post=551"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}