Protocol

Authentication

Different ways to authenticate HTTP requests.

Apps create and hold a public/private key pair that they use to sign requests. The private key is never shared with anyone.

  • An app generates a new key pair.

  • The public key is shared with the server during registration­.

  • Every request is signed with the private key.

This is the standard way to authenticate requests for the HTTP API. It follows the BAQ Authentication Scheme and should be a string with the following format:

Authorization: BAQ algorithm="..." ts="..." nonce="..." id="..." headers="..." signature="..."

Parameters

  • id string

  • algorithm enum

    • Algorithm used to sign this request.

      • ed25519: Only algorithm currently supported.
  • ts int

  • nonce string

    • Random string unique to this request.

    • Maximum of 10 characters.

  • headers string

    • List of special headers used in this request.

    • Lowercase and comma-separated.

    • Accepted headers:

      • range
      • x-baq-client-id
      • x-baq-content-sha256
      • x-baq-publickey
      • last-event-id
  • signature string

    • Base64 encoded signature.

Signature

Signing the request is done by assembling a signature input string and running it through the signing algorithm. It has the following format:

baq.request
{algorithm}
{ts}
{nonce}
{authorization_id}
{HTTP_METHOD}
{path_and_query}
{host}
{port}
{header1=value1}
{header2=value2}

  • authorization_id is obtained through the authorization flow­.

  • HTTP_METHOD is all uppercase.

  • Each line ends with a newline \n character.

  • Each header has its own line.

  • Order of headers is the same as in Authorization value.

There are situations when it’s not possible to supply a custom header value. For such cases, the protocol allows a bearer query string parameter to be generated that allows anyone in its possession to access the corresponding resource through a GET request for a limited time.

  • Example 1: Set the source of an <img> tag.

  • Example 2: Make the browser download a file.

  • Example 3: Allow a blob to be cached.

Token value

The token itself is a Base64 encoded string with the following format:

{id}\{ts}\{signature}

Parameters

  • id string

  • ts int

  • signature string

    • Base64 encoded signature.

Signature

Signing the request is done by assembling a signature input string and running it through the signing algorithm. It has the following format:

baq.url
{algorithm}
{ts}

{authorization_id}
GET
{path_and_query}
{host}
{port}

  • authorization_id is obtained through the authorization flow­.

  • Each line ends with a newline \n character.

  • The empty line is because tokens don’t have a nonce.

Most requests to the HTTP API are authenticated with the Authorization header. Here, we want to authenticate a request to fetch a single record.

Initial data:

+----------------------+----------------------------------------------+
| App record ID        | 4bae3e86828a44fc96b78cd0d5a4b7ae             |
+----------------------+----------------------------------------------+
| Authorization ID     | 430aaa3623da40c9a548182b80453656             |
+----------------------+----------------------------------------------+
| Private key (Base64) | IaqavlYBOqnUpqGfZ0cSH/7WgA3fNjGwZNpf65cM9Hc= |
+----------------------+----------------------------------------------+
| Timestamp            | 1710884802348                                |
+----------------------+----------------------------------------------+
| Nonce                | 573hf2jg                                     |
+----------------------+----------------------------------------------+

From these, we build the signature input. We add a X-Baq-Client-Id header with a random value to uniquely identify our client.

baq.request
ed25519
1710884802348
573hf2jg
430aaa3623da40c9a548182b80453656
GET
/api/alice/records/alice.baq.run/430ed5e38a0c4002a62f81e497820c5c
baq.run
443
x-baq-client-id=8fbf7696f25b4628bde73f46f4631d3f

We use the private key to sign that string, which results in:

wVdBX9VKGJHhWBWOwiT9NH5ELHgMYt36JFqN+aiPVbeCWyMT85KgjemVemKQxw2m0ZYMfsQ6kV92uraJkyUWCQ==

We can now perform the full request:

GET /api/alice/records/alice.baq.run/430ed5e38a0c4002a62f81e497820c5c HTTP/2
Host: baq.run
X-Baq-Client-Id: 8fbf7696f25b4628bde73f46f4631d3f
Authorization: id="4bae3e86828a44fc96b78cd0d5a4b7ae" algorithm="ed25519" ts="1710884802348" nonce="573hf2jg" headers="x-baq-client-id" signature="wVdBX9VKGJHhWBWOwiT9NH5ELHgMYt36JFqN+aiPVbeCWyMT85KgjemVemKQxw2m0ZYMfsQ6kV92uraJkyUWCQ=="

To set a blob as the source for an <img> tag and let the browser download it, we need to build a bearer token. Blobs can only be accessed through a record, so this will also be part of the URL.

Initial data:

+----------------------------+----------------------------------------------+
| App record ID              | 4bae3e86828a44fc96b78cd0d5a4b7ae             |
+----------------------------+----------------------------------------------+
| Authorization ID           | 430aaa3623da40c9a548182b80453656             |
+----------------------------+----------------------------------------------+
| Private key (Base64)       | IaqavlYBOqnUpqGfZ0cSH/7WgA3fNjGwZNpf65cM9Hc= |
+----------------------------+----------------------------------------------+
| Expiration timestamp (+2h) | 1710892002348                                |
+----------------------------+----------------------------------------------+

From these, we build the signature input.

baq.url
ed25519
1710892002348

430aaa3623da40c9a548182b80453656
GET
/api/alice/records/alice.baq.run/430ed5e38a0c4002a62f81e497820c5c/blobs/66a045b452102c59d840ec097d59d9467e13a3f34f6494e539ffd32c1bb35f18/thumbnail.jpg
baq.run
443

We use the private key to sign that string, which results in:

XzYooYb6s1SxQp0EUrNDyg8KN6e84wX8FzKTQ3QTDbbFz7Y2j1MOJE+UlrXosxUw0dhDbRPB3ElozFs4RE79DA==

We can now build the id\ts\signature token:

4bae3e86828a44fc96b78cd0d5a4b7ae\1710892002348\XzYooYb6s1SxQp0EUrNDyg8KN6e84wX8FzKTQ3QTDbbFz7Y2j1MOJE+UlrXosxUw0dhDbRPB3ElozFs4RE79DA==

Once Base64 encoded this gives us:

NGJhZTNlODY4MjhhNDRmYzk2Yjc4Y2QwZDVhNGI3YWVcMTcxMDg5MjAwMjM0OFxYellvb1liNnMxU3hRcDBFVXJORHlnOEtONmU4NHdYOEZ6S1RRM1FURGJiRno3WTJqMU1PSkUrVWxyWG9zeFV3MGRoRGJSUEIzRWxvekZzNFJFNzlEQT09

Everything is now ready to display the image:

<img
  src="https://baq.run
       /api/alice/records/alice.baq.run/430ed5e38a0c4002a62f81e497820c5c/blobs/66a045b452102c59d840ec097d59d9467e13a3f34f6494e539ffd32c1bb35f18/thumbnail.jpg
       ?bearer=NGJhZTNlODY4MjhhNDRmYzk2Yjc4Y2QwZDVhNGI3YWVcMTcxMDg5MjAwMjM0OFxYellvb1liNnMxU3hRcDBFVXJORHlnOEtONmU4NHdYOEZ6S1RRM1FURGJiRno3WTJqMU1PSkUrVWxyWG9zeFV3MGRoRGJSUEIzRWxvekZzNFJFNzlEQT09"
/>
© 2024 Quentez