Wheelhouse docs

Single sign-on with an OIDC provider#

You will end up with people signing in to the router through your identity provider, with their group membership deciding their role — so removing somebody from a group at the provider removes their write access at their next sign-in, without anybody editing Wheelhouse.

The agent is an OIDC relying party: authorization code with PKCE, ID-token verification, one provider, configured by options on the agent's system service.

Before you start#

  • Console or SSH access to the router. Single sign-on is set up at the console, not in the web interface, so a provider misconfiguration cannot lock the web interface behind itself. The web interface has no screen for it.
  • An OIDC provider you control, and the ability to register a client on it.
  • The groups you will map to roles.

Step 1 — Register the client at the provider#

Register exactly one redirect URI:

https://<router>:8443/api/oidc/callback

Note the client ID and client secret.

Step 2 — Put the secret in a file#

At the router's console, or over SSH:

bash
sudo sh -c 'umask 077; cat > /config/wheelhouse/oidc-secret'
# paste the secret, then ctrl-D

The agent refuses to read a secret file that is group- or world-readable. /config is the persistent partition, so the file survives an image upgrade; /config/wheelhouse/ is where the agent keeps its other secrets. Nothing reads the file until you add the option that names it.

Step 3 — Add the options with a drop-in#

Not by editing the packaged unit, which an image upgrade replaces.

/etc/systemd/system/wheelhouse-agent.service.d/oidc.conf
[Service]
ExecStart=
ExecStart=/usr/bin/wheelhouse-agent … \
  --oidc-issuer https://auth.example.com/application/o/wheelhouse/ \
  --oidc-client-id wheelhouse \
  --oidc-client-secret-file /config/wheelhouse/oidc-secret \
  --oidc-redirect-url https://192.0.2.1:8443/api/oidc/callback \
  --oidc-admin-groups homelab-admins \
  --oidc-operator-groups wheelhouse-ops

Repeat every option the packaged unit already passes where the … is; the empty ExecStart= clears the original. Then:

bash
sudo systemctl daemon-reload
sudo systemctl restart wheelhouse-agent

Pin --oidc-redirect-url if the agent is reachable under more than one name, so the flow never depends on which name the browser happened to use. Without it the URL is derived per request from the incoming origin.

--oidc-label is the provider's name on the sign-in button. It defaults to Authentik.

Step 4 — Understand what a sign-in from the provider may do#

Four rules govern it.

Link is by subject. sub is the provider's unchanging identifier for a person, and the Wheelhouse account holding that subject is the account the sign-in becomes. An account with a subject and no password signs in through single sign-on only.

An unknown identity is provisioned, or refused. --oidc-provision (on by default) creates an account named from --oidc-username-claim (default preferred_username) with --oidc-default-role (default viewer). If a local account already has that name and no subject, the sign-in is refused — provisioning never attaches a sign-in to an account that already exists. Link that account by hand instead, below.

Groups decide role when --oidc-admin-groups or --oidc-operator-groups is set, at every sign-in. The claim is --oidc-groups-claim (default groups; some providers nest it differently). Mapping will not demote the only admin.

Email is never an identity by default. --oidc-link-by-email exists, is off, and refuses an address the provider has not marked email_verified.

Step 5 — Sign in#

The sign-in screen shows Continue with Authentik — or whatever --oidc-label says — above the password form, which follows under "or a local account". While the provider is not answering, the button is disabled and the screen says "The identity provider is not answering." with the reason.

Linking an account that already exists#

Admin → Users, the person's row, Single sign-on → Identity provider ID: "The provider’s ID for this person, not their email. Empty unlinks the account." Enter their sub and choose Save changes; their next sign-in through the provider lands in that account. The agent refuses a subject that another account already holds.

The Users table's Single sign-on column shows which accounts are linked, and its Password column reads None, single sign-on only for an account with no password of its own.

Two consequences#

Password sign-in, two-factor authentication, API tokens and the break-glass token all keep working. An agent that could only be entered through a provider would be one provider outage from unmanageable.

The session cookie is marked Secure whenever the browser is on HTTPS — the agent's own TLS, or a forwarded https scheme under --trust-proxy — and not on a plain-HTTP origin. There the browser would discard a Secure cookie: the sign-in would succeed, and every request after it would be refused as unauthorized.

What the unauthenticated routes give away#

Check it worked#

Sign in through the button, as somebody with no local account, and confirm:

  • an account appeared on Admin → Users with the name from the username claim, linked in the Single sign-on column;
  • its role matches the group you put the person in;
  • the audit log (System → Audit log tab) has "Created an account through single sign-on", and attributes their next change to that name.

That person's Account page has a Single sign-on panel: the provider, whether it is answering, and the identity the account is linked to.

The provider's settings, the group mapping and every linked account are also available to an admin from the API:

bash
R=https://<router>:8443
T=wh_...                                    # an admin token
curl -sk -H "Authorization: Bearer $T" "$R/api/admin/oidc"

Then remove somebody from a group at the provider and confirm their role changes at their next sign-in. That is the property you set this up for; test it once.

Undoing it#

At the console, remove the drop-in and restart:

bash
sudo rm /etc/systemd/system/wheelhouse-agent.service.d/oidc.conf
sudo systemctl daemon-reload
sudo systemctl restart wheelhouse-agent

Provisioned accounts stay. Give the people who need them a password — Admin → Users, their row, Password → New password — or delete the accounts: Add an operator.

A person can detach their own account with Unlink on the Single sign-on panel of their Account page. It is disabled while the account has no password of its own: "Set a password first".

See also#

Updated 2026-09-18 oidc sso authentik