Biscuits and Web Links

Posted on September 22, 2023 by Rickard Nilsson

About one year ago, we introduced an HTTP API for This API can be used to retrieve information about the builds you’ve run on the service. One place where the API is used is in the GitHub Action nixbuild-action to create detailed build summaries at the end of workflow runs.

When the API was launched, it was using Biscuit auth tokens to handle authentication and authorization. In the initial implementation, we didn’t really take much advantage of Biscuit, and basically used them as plain API keys. This week, however, we’ve finally expanded our Biscuit usage to properly take advantage of the flexibility offered.

Read on to find out how this allows us to now support advanced access policies, token-based SSH auth and signed web links that gives easy access to build logs and fancy build reports.

Let’s start out with the feature we’re really happy to launch: signed web links. To show how it works, I grep for a broken package in nixpkgs and find one called textpieces. Then I try building it on my laptop which has been setup to use as a remote builder (we need NIXPKGS_ALLOW_BROKEN=1 and --impure in order to force Nix to evaluate the broken package):

$ NIXPKGS_ALLOW_BROKEN=1 nix build --impure nixpkgs#textpieces

error: build of '/nix/store/s7ns32ymdf9iq44hpa62dkdbwlhvc7nx-textpieces-3.4.1.drv' on 'ssh://' failed: builder for '/nix/store/s7ns32ymdf9iq44hpa62dkdbwlhvc7nx-textpieces-3.4.1.drv' failed with exit code 1
error: builder for '/nix/store/s7ns32ymdf9iq44hpa62dkdbwlhvc7nx-textpieces-3.4.1.drv' failed with exit code 1;
last 10 log lines:
> upgrade: Use the '$' extern syntax introduced in blueprint 0.8.0
> at ../resources/ui/CustomToolPage.blp line 43 column 3:
>   43 |  .TextPiecesToolSettings tool_settings {
>      |  ^
> error: Cannot convert 2.5 to integer
> at ../resources/ui/Editor.blp line 45 column 26:
>   45 |          margin-bottom: 2.5;
>      |                         ^
> ninja: build stopped: subcommand failed.
> [] See this link for build details and logs:
       For full logs, run 'nix log /nix/store/s7ns32ymdf9iq44hpa62dkdbwlhvc7nx-textpieces-3.4.1.drv'.

At the very end of the build we see the message [] See this link for build details and logs, pointing us to[…].

Go ahead and try that link now! What you’ll find is a page with details of the build we just ran, along with its full build logs. This also works for builds that don’t fail. Every build you run on will get this handy summary link printed in the end of the build. You can share those links as you please, just like I did here. No accounts or logins on are needed to access the links.

You can explicitly create a build link for any build you’ve run using the builds url command in the adminstration shell, or by using the new HTTP API endpoint.

Biscuit Auth Tokens

So how do these build links work? The t= argument in the links is a Biscuit auth token, and we can use the biscuit-cli tool to inspect it:

$ echo >token "EtcBCm0KBWJ1aWxkCgpidWlsZDpyZWFkGAMiCAoGCAcSAhABIg0KCwgEEgc6BQoDGIEIMiYKJAoCCBsSBggFEgIIBRoWCgQKAggFCggKBiCZzeO0BgoEGgIIADIVChMKAggbEg0IAhIDGIAIEgQQ9IFyEiQIABIgKYLCEYA2IZ9hybF7HQni7n68uipmGCexG7F4x0KMH2oaQOVIWFexkOoOpgNYWNXNv9GY6I5bO5T1n6RBQvU6D25_XTJm41Dmj4_fKPmzc9aZrt4rhxGBZafirifzKecFPgkiIgogIsQ6_jdmw1s5IhuXrrPabnGXJuoGoKrpfIUHz1uUU2k="

$ biscuit inspect ./token

Authority block:
== Datalog ==
check if time($time), $time < 2024-07-18T09:55:37Z;
check if resource("build", 1868020);

== Revocation id ==


🙈 Public key check skipped 🔑
🙈 Datalog check skipped 🛡️

What you see above is Biscuit Policy Language. It states that the owner of the token is 1, which is an internal id of my own account on Then it says the token has the build:read right. That means that you can only use this token for reading information about builds. You can’t use it to run builds, or fetch store paths or anything like that. Furthermore, there are two check statements in the token. One of them sets an expiration time of the token, and the other one restricts the token to requests concerning a specific resource, namely the build with id 1868020.

Now, the really interesting thing about Biscuit tokens is that you can yourself restrict the tokens further, without involving the service at all. This process is called attenuation. We can for example set a new expiration time on the token like this:

$ biscuit attenuate --block 'check if time($time), $time < 2023-10-01T00:00:00Z;' ./token


Now, we got a new auth token with our additional restriction added to it. The interested reader can try to use the new token as t= parameter. This should work fine as long as the current date is before 2023-10-01.

To learn more about Biscuit tokens and policies I recommend reading through our new Access Control documentation, and of course also the Biscuit documentation.

Using Auth Tokens for Everything

As part of the launch of the signed web links, we have implemented support for using auth tokens in all parts of You can use them for accessing the HTTP API or when using the Nix client to run builds or interact with your Nix store in

You can create tokens using the tokens create command in the administration shell of When doing this, you select what permissions you want to embed in the token, and set an expiration time. With the permission system it is possible to create tokens that can only be used for specific operations in

When you have created a token, you can create new, more restricted tokens from it, using the attenuation process demonstrated above.

You can still use SSH keys for auth, if you like. In fact, the newly introduced permissions are also possible to assign to specific SSH keys, using the default-permissions setting. This way, you can gain some more granularity in your authorization setup, without going all in on Biscuit tokens.

The Future

For now, the access policies you are able to define in your auth tokens are somewhat limited since the policy context is still something we are expanding. The context is represented as a set of facts that are made available by during the authorization phase. We are working on adding more facts, and also implementing more example policies that you can gain inspiration from. As always, if you have any feedback, questions or issues, just ping us on [email protected].