Tent v0.3-WIP Documentation

Note well: There is no guarantee of API stability until Tent v1.0.

Please contribute by making Pull Requests and Issues on the GitHub repository.


Tent uses the Hawk HTTP authentication scheme (v1.0).


Hawk is an authentication scheme built around HMAC digests of requests and responses. Every authenticated client request has a Authorization header containing a MAC and some metadata, and each server response to authenticated requests contains a Server-Authorization header that authenticates the response.

In Tent, the credentials used with Hawk are provided in credentials posts. The id of the post is the Key ID in Hawk. Tent currently only supports the sha256 hash algorithm, used for HMAC and payload validation.

Request Header

The request Authorization header consists of fields in key="value" format:

Field Required Description
id Required The Key ID. In Tent, this is the id of the credentials post.
ts Required The timestamp in seconds since the Unix epoch. It must be within ±60 seconds of the server timestamp. If there is too much skew, an error will be returned.
nonce Required A randomly generated string. This must be unique for each request.
mac Required The base64-encoded MAC of the normalized string.
ext Optional Application-specific data. Currently unused in Tent.
hash Optional The base64-encoded digest of the request payload.
app Optional The app ID (id from the app post). Required if the request is from an app.
dlg Optional The app delegate. Currently unused in Tent.


Authorization: Hawk id="qUtGgNr7YTURDensMvGa1g", mac="mMiuXNaaEmw1alE15fU12ItH9jyKHlfh4/uZ14Lr6k8=", ts="1368116073", nonce="Wiok05gO", app="2HjRl8gWz5shfSXrwblRnw"

Response Header

All responses to authenticated requests contain a Server-Authorization header. The header is in the same format as the Request Header, but does not have as many fields. The mac field is always included, and is based on all of the same data provided in the request, except the hash and ext values are replaced with response-specific values and the string header is different. The hash is optional and is a digest of the response payload.


Server-Authorization: Hawk mac="YWojrFVgIjgd+RiPacnDwRcL8VtvcMEzahVfOpoLxoA=", hash="yAF3A3y3uzLvNT2m/nVwsifn1+joCqu0uNWZS8RSv6Y="

Normalized String

The normalized string forms the HMAC digest value of the mac field. It is based on request details, and consists of field values followed by newlines. Some fields are also included in the request header/bewit.

Field Description
Header Specifies the MAC type, one of hawk.1.header (request header), hawk.1.response (response header), hawk.1.bewit (request bewit).
ts The timestamp in seconds since the Unix epoch.
nonce A randomly generated string.
Method The HTTP request method, all letters capitalized.
Request URI The HTTP Request-URI, as sent in the request. Typically this is just the absolute path and query parameters.
Host The HTTP host, as sent in the Host header, port omitted, all lowercase or if no Host is sent, the IP address.
Port The port connected to, typically this will be 443.
hash The base64 encoded payload digest, blank if none.
ext The app-specific data, blank if none.
app The app id, omitted if none.
dlg The app delegate, omitted unless app is set, blank if app is set.
Request URI

Example with app



Example: response with hash, no app


Payload Validation

Clients and servers may optionally validate payloads (request/response bodies). There is no requirement to do so, but it is strongly recommended where possible.

The payload digest is of a header and the content type, each followed by a newline, then the payload itself, also followed by a newline. The content type is as provided in the Content-Type header and stripped of all parameters and leading/trailing whitespace.


Thank you for flying Hawk

Timestamp Skew

When the client timestamp skew is outside of ±60 seconds of the server, the server will return 401 response code with a WWW-Authenticate header containing the server timestamp. The offset must be calculated from this timestamp, and applied to all future requests.

The included tsm field is a HMAC of a header and the timestamp each followed by a newline to prevent malicious skew attacks.


WWW-Authenticate: Hawk ts="1365741469", tsm="b4Qqhz8OUBq21saghHLV1ktwlXE72T1xtTEZkSlWizA=", error="Stale timestamp"

MAC data


URL Signing

Pre-signed URLs may be created, allowing temporary read access to the bearer of the URL. These are called bewit URLs and have an added bewit URL parameter. To construct the bewit value, join the fields with \, base64 the string using the URL character set, and then strip all trailing =.

The request method in the normalized string is always GET, and the server allows GET and HEAD requests. The nonce field in the normalized string is always empty.

Field Description
id The Key ID.
ts The expiry timestamp. The URL is valid until the server clock passes this time.
mac The base64-encoded HMAC digest of the normalized string.
ext Application-specific data. Empty if not set.


trim-right(base64-url("id\ts\mac\ext"), "=")

Test Vectors


Field Value
Key HX9QcbD-r3ItFEnRcAuOSg
Host example.com
Port 443
Request Method POST
Request URI /posts
Content-Type application/vnd.tent.post.v0+json
Payload {"type":"https://tent.io/types/status/v0#"}

App request w/hash

Authorization: Hawk id="exqbZWtykFZIh2D7cXi9dA", mac="2sttHCQJG9ejj1x7eCi35FP23Miu9VtlaUgwk68DTpM=", ts="1368996800", nonce="3yuYCD4Z", hash="neQFHgYKl/jFqDINrC21uLS0gkFglTz789rzcSr7HYU=", app="wn6yzHGe5TLaT-fvOPbAyQ"


Server Response

Server-Authorization: Hawk mac="lTG3kTBr33Y97Q4KQSSamu9WY/mOUKnZzq/ho9x+yxw="


Relationship Request

Authorization: Hawk id="exqbZWtykFZIh2D7cXi9dA", mac="OO2ldBDSw8KmNHlEdTC4BciIl8+uiuCRvCnJ9KkcR3Y=", ts="1368996800", nonce="3yuYCD4Z"


Server Response w/hash

Server-Authorization: Hawk mac="LvxASIZ2gop5cwE2mNervvz6WXkPmVslwm11MDgEZ5E=", hash="neQFHgYKl/jFqDINrC21uLS0gkFglTz789rzcSr7HYU="


Timestamp Skew Error

WWW-Authenticate: Hawk ts="1368996800", tsm="HPDcD5S3Kw7LM/oyoXKcgv2Z30RnOLAI5ebXpYDGfo4=", error="Stale timestamp"


Bewit (GET /posts)