kineuroExperimental Neuroradiology Research
Karolinska Institutet

Who may call the engine

One flag decides: nobody signs in, tokens name callers, or an identity provider does. What a caller holds is a set of grants and a detail level.

The wizard does this for you. This page is what it does, for when you would rather do it yourself.

What a caller may do is a set of grants and a detail level. A grant opens the doors of a page, such as query:see or data:work, and the detail level, plain, quasi or sensitive, says how much of a record the caller sees; groups and grants lists them. The old names still stand for their sets wherever a caller is described: reader, reviewer, operator and admin, and assist for the assistant. How a caller gets them is --auth.

off: the local person

nils serve --auth off --bind 127.0.0.1:8437 \
  --registry /srv/nils/registry --pack-dir /srv/nils/packs

The caller is whoever reached the port, and holds every grant and sees everything. Bound to 127.0.0.1, that is the person at the machine, which is exactly right for a laptop. It is the wrong mode for anything a network can reach: there is no login to fail.

This is what the desk’s off mode expects.

token: a token names the caller

nils serve --auth token \
  --token "a-long-random-string=anna@lab:reviewer" \
  --token "another-long-string=pipeline@lab:pipelines:work,release:work" \
  --bind 127.0.0.1:8437 --registry /srv/nils/registry --pack-dir /srv/nils/packs

Each token names its principal and what it holds, comma separated: grants, old names standing for their sets, or both. Without a list it holds every grant and sees everything, which is what a machine token is, and the engine says so as it starts; with an empty list it holds nothing and is refused at every door. NILS_TOKENS takes the same tokens, each with its list, comma separated, so tokens need not sit in the process table.

Tokens are for programs. For people on a shared machine, install the desk in local mode: it keeps the users, their passwords and their groups, mints a short-lived token for each of them, and the engine runs as in the next section with the desk as its issuer.

oidc: an identity provider decides

The engine validates each token itself. A token the desk signed carries the person’s grants and detail, which the engine reads as they are; a provider’s own token names groups, which --role maps.

nils serve --auth oidc \
  --oidc-trust issuer=https://nils.example.org,audience=nils,jwks=https://nils.example.org/.well-known/jwks.json,keep_subject=true \
  --oidc-trust issuer=https://auth.example.org/application/o/nils/,audience=<client id>,jwks=https://auth.example.org/application/o/nils/jwks/ \
  --oidc-groups-claim roles \
  --role reader=reader --role reviewer=reviewer \
  --role operator=operator --role admin=admin \
  --bind 127.0.0.1:8437 --registry /srv/nils/registry --pack-dir /srv/nils/packs
  • --oidc-trust issuer=URL,audience=ID,jwks=URL|FILE[,keep_subject=true] is one issuer, its audience and its keys, and repeats for more. A caller is named subject@issuer host. With keep_subject=true, a subject that already holds an @ is the name as it is: give it only to the desk’s own entry, since the desk names each person as the provider’s subject at the provider’s host.
  • --oidc-groups-claim is the claim the groups arrive in, groups unless set.
  • --role GROUP=NAME gives a group an old name, standing for its set, or one grant. It repeats, one name each time.

A token’s grants and what its groups give add up, and the higher detail holds. For the desk in local mode, the desk’s entry alone is enough.

A caller that holds no grant is refused at every door with 403 and “holds no grant”. That is the state a new colleague is in until somebody puts them in a group, and the desk says so rather than showing an error.

The desk’s registration command prints this whole line for you: see the desk with an identity provider.

What a caller holds

GET /api/capabilities names the caller’s grants and detail, and the grant each door needs. A caller without a door’s grant, or below its detail, is refused with 403 and what the door needs. A job queued at the door keeps the detail of whoever queued it, so it never reads more than they could. A job queued at the keyboard with nils jobs enqueue records the keyboard’s reach: every grant at every detail, and sealed:see only where --unsealed-access gave a reason.

A request may carry X-Nils-Ceiling with an old name, such as reviewer: for that request the engine keeps only the grants that name stands for, and lowers the detail to it. The assistant sends one for each of its stations.

What the engine records

Every call is audited with the principal, the door, what it touched and when, whatever the mode. In off mode that is the local user’s name; it is still a record.

Next: as a service.

Updated 17 October 2026