OIDC support in nixbuild.net

Posted on September 1, 2025 by Rickard Nilsson

nixbuild.net now supports OpenID Connect (OIDC)!

This means that you can create auth tokens that are only usable if you also can provide an OIDC JWT signed by a specific identity provider. In practice, you can now configure your GitHub Actions workflow with a nixbuild.net auth token that can only be used from within GitHub’s infrastructure. You can even lock it down to specific GitHub repositories. This is a great step forward in securing nixbuild.net’s authentication and authorization.

This new feature is not specific to GitHub, but can be used together with any OIDC provider. Additionally, it is implemented on top of the existing Biscuit support in nixbuild.net. This further validates the usefulness and flexibility that nixbuild.net’s Biscuit policies provide.

Read on to find out exactly how it all fits together!

A Usage Example

Let’s illustrate how OIDC works in nixbuild.net by working our way through a complete usage example. The repository used in this example is available for inspection at GitHub.

Our objective is to configure a GitHub Actions workflow that uses nixbuild.net to perform Nix builds. We want to make use of OIDC to secure the nixbuild.net authentication and avoid the impact a workflow auth token leak could have.

We have three steps to go through:

  1. Create a new nixbuild.net auth token with the base permissions needed for our GitHub workflow.

  2. Derive a new token from the original one, with a Biscuit policy that takes the OIDC context into account. This process is called attenuation and is done offline from nixbuild.net, on your local computer. Arguably, the nixbuild.net UI could offer a way to attach a Biscuit policy directly during token creation, but there is no such functionality yet.

  3. Create a GitHub Actions workflow that requests an OIDC JWT from GitHub and passes it on to nixbuild.net.

Step 1: Create a Base Token

Create a new nixbuild.net auth token using the nixbuild.net admin shell or the web UI. This token defines the “upper limit” of what our workflow can do on nixbuild.net. Since you probably want your workflow to be able to run builds on nixbuild.net, add the permissions build:read, build:write, store:read and store:write, but leave out account:read and account:write. You can set the expiration time to whatever makes sense to you. It is possible to set a shorter expiration time on the attenuated token (next step) if you like.

The token generated in this step can be kept entirely offline, and you can then derive new tokens from it whenever you like. Or, you could simply throw away this base token once you have created an attenuated token. Just remember to not revoke the base token in nixbuild.net because that will implicitly revoke all derived tokens too.

If you use the web UI, creating the token should look something like this:

The created token is a long string of randomly-looking characters. Store this string to a file on your computer and treat it as a secret. If anyone gets their hands on it, they will be able to run builds on nixbuild.net, possibly incurring costs to your account.

Step 2: Attenuate the Base Token

Now we want to create a token with more restrictions than the base token. This restricted token will be used by your GitHub workflow. The process of creating a new token from an existing one is called “attenuation”, in Biscuit lingo.

To perform attenuation you need the Biscuit CLI tool, biscuit-cli. It is available in nixpkpgs:

$ nix shell nixpkgs#biscuit-cli

You can use this tool to inspect your base token (stored in the file base.token in this example):

$ biscuit inspect base.token

In the printed output you should be able to see the permissions and expiration time that you selected during token creation.

Now we’ll write a Biscuit authorization policy that restricts token usage to only work from within GitHub Actions workflows for the nixbuild/nixbuild-oidc-auth-example repository:

check if
  jwt_claim("iss", "https://token.actions.githubusercontent.com");

check if
  jwt_claim("sub", $sub),
  $sub.contains("repo:nixbuild/nixbuild-oidc-auth-example");

We add two check statements, which say what must hold true for authorization to succeed. jwt_claim refers to a Biscuit fact that is added by nixbuild.net if it has been provided an OIDC JWT and been able to verify the signature of the JWT. We’ll talk more about how the JWTs are passed to nixbuild.net in the next section.

nixbuild.net will not add all JWT claims as Biscuit facts, since it would make the authorization process computationally more expensive. But it adds the iss and sub claims, which are used above. In our policy, we first verify the iss claim. When nixbuild.net receives a JWT with an iss claim, it will use OIDC Discovery to find out which endpoint to ask for public keys to perform JWT verification. This is what makes the OIDC support in nixbuild.net generic. You could even host your own identity provider, as long as it supports OIDC Discovery.

So, when our policy checks that the iss claim is https://token.actions.githubusercontent.com, we can be sure that the provided JWT was issued by GitHub.

Furthermore, in GitHub’s reference documentation we can see that the sub claim will include the owner and name of the repo that created the OIDC JWT. We use that information to write our second policy check. GitHub encodes more information in the sub claim that can be useful for authouring Biscuit policies. Check out their documentation for details! Also be sure to read through the Biscuit language documentation to find out what functions and operators you can use in your policies! There is also a helpful Bisuit playground available.

Finally, we save our policy to a file (gha-oidc.biscuit in this example) and then use the Biscuit CLI to attach the policy to our base token, creating a new, attenuated, token:

$ biscuit attenuate --block-file gha-oidc.biscuit base.token > gha-oidc.token

If you run biscuit inspect gha-oidc.token you should see that it includes our new policy.

Lets do a quick sanity check to see that the token actually can’t be used outside GitHub. We do this by performing a HEAD request against the /builds endpoint of the nixbuild.net HTTP API, once with the base token and once with the attenuated token:

$ curl -sIH "Authorization: Bearer $(cat base.token)" https://api.nixbuild.net/builds
HTTP/2 200
server: nginx
date: Thu, 28 Aug 2025 09:31:47 GMT
content-type: application/json;charset=utf-8

$ curl -sIH "Authorization: Bearer $(cat gha-oidc.token)" https://api.nixbuild.net/builds
HTTP/2 403
server: nginx
date: Thu, 28 Aug 2025 09:32:02 GMT

Looks good! Now lets see how to use the token in an actual GitHub Actions workflow.

Step 3: Create a GitHub Workflow

The action nixbuild/nixbuild-action is the preferred way of configuring nixbuild.net in GitHub Actions workflows, and since v21 it supports generating an OIDC ID Token and passing it on to nixbuild.net automatically.

Here is a simple workflow that does this:

name: oidc-test

on: push

jobs:

  oidc-example:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Install Nix
        uses: nixbuild/nix-quick-install-action@v33

      - name: Configure nixbuild.net
        uses: nixbuild/nixbuild-action@v21
        with:
          nixbuild_token: ${{ secrets.nixbuild_token }}
          oidc: true

      - name: Run a simple test build on nixbuild.net
        run: |
          export DRV_SEED="$RANDOM$RANDOM"
          nix build github:nixbuild/nixbench#write-one-file \
            --impure \
            --eval-store auto \
            --store ssh-ng://eu.nixbuild.net \
            --print-build-logs

The important pieces are the id-token: write permission (allows OIDC ID Tokens to be fetched from GitHub), the oidc: true setting for nixbuild/nixbuild-action (enables the mechanism that fetches and passes OIDC ID Tokens on to nixbuild.net) and the nixbuild_token secret (should be set to the attenuated Biscuit token).

The above workflow is all it takes to integrate GitHub’s OIDC with nixbuild.net. If you are using some other OIDC Provider, or if you’re not using nixbuild-action you should pass in your OIDC ID Token to nixbuild.net by setting the SSH environment variable (or HTTP header, if you’re using the HTTP API) named NIXBUILDNET_OIDC_ID_TOKEN. The OIDC ID Token should have the audience nixbuild.net.