authd: option to hide the local broker from the GDM broker picker for OIDC-only deployments
- Dominant language
- Go
- Stars
- 308
- Forks
- 41
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 58
Description
## Summary
For deployments where every authenticated GDM user is expected to come from a single configured broker (e.g. an OIDC broker pointed at the org's IdP), the **`local` broker is unconditionally surfaced in the GDM broker picker** when the user clicks "Not listed?" → enters their email. There is currently no way to hide it.
In our deployment (corporate laptops, Okta as the only intended sign-in path, plus a vault-managed local `recovery` admin account that operators only ever reach via TTY or out-of-band sudo) this causes real user confusion: end-users see two buttons — `OIDC` (or whatever `name = ...` is set to in `oidc.conf`) and `local` — and pick `local`, which then prompts for a Unix password they don't have. The result is identical to #1359: an apparent "wrong password" dead end at GDM, with no diagnostic.
The IT team's specific feedback was: *"users don't expect to be able to have a local account; the `local` button is confusing, please hide it."*
## Versions
- `authd` deb 0.5.5 from `ppa:ubuntu-enterprise-desktop/authd` on Ubuntu 24.04.3
- `authd-oidc` snap 0.4.0 (patched per #1476 + #1496, but unrelated to this issue)
- Identity provider: Okta Org Authorization Server
## Why the existing knobs don't address this
- **#1234 (`disable_local_password` in `broker.conf`)** affects the **OIDC broker's own** `Password` auth mode (the post-OIDC "set offline password" prompt), not the `id="local"` broker registered by the daemon. The local button in the picker would still appear.
- **#1124** (per-PAM-service disable, e.g. `disable_local_password = gdm`) is the right shape and I see @adombeck's sketch in the comments matches our use case, but it's been backlogged and the `jira` label was removed in Jan; we'd love to see this revived (and would gladly contribute) but want to flag the narrower picker-only flavour separately because it's a much smaller change.
- Removing the local broker's `.conf` doesn't help — there is no `.conf`. The local broker is registered unconditionally:
```go
// First broker is always the local one.
b, err := newBroker(ctx, "", nil)
brokersOrder = append(brokersOrder, b.ID)
brokers[b.ID] = &b
```
([`internal/brokers/manager.go`](https://github.com/canonical/authd/blob/main/internal/brokers/manager.go), `NewManager`)
## What "hide" means here
Important: hiding the local broker from the **picker UI** only is enough. The daemon should still register it so internal consumers (`BrokerFromSessionID("")`, NSS lookups for already-bound users, etc.) keep working. The change is purely "don't ship `id="local"` to GDM in the `brokersReceived` event when the operator opts in."
For users in our setup, hiding the local broker from the picker has no functional regression:
- The local recovery user can still log in via TTY (Ctrl+Alt+F2–F6), since TTYs don't go through the broker picker.
- The local recovery user can still log in via GDM when picked from the user list / typed by name — GDM bypasses the picker for already-known users assigned to the local broker.
- Sudo, screen-unlock, etc. continue to use the local password normally.
## Proposed shape
A daemon-level config knob, off by default, e.g. in `/etc/authd/authd.yaml`:
```yaml
# When true, the local broker is registered as usual but is filtered out of the
# AvailableBrokers() response sent to the broker chooser (typically GDM). Use this
# in OIDC-only deployments where a "local" entry in the picker is confusing and
# never selectable to a meaningful outcome.
hide_local_broker_in_picker: false
```
Implementation is ~10 lines in `Manager.AvailableBrokers()`:
```go
func (m *Manager) AvailableBrokers() (r []*Broker) {
for _, id := range m.brokersOrder {
if m.hideLocalInPicker && id == LocalBrokerName {
continue
}
r = append(r, m.brokers[id])
}
return r
}
```
Plus daemon-config plumbing and a test. Happy to file the PR if the API is acceptable; please tell me if you'd prefer a different flag name, scope (per-broker config vs daemon config), or shape.
## Workaround we are using today
None inside `authd`. We've considered carrying a downstream-patched `authd` deb with the filter applied unconditionally, but would much prefer an upstream knob.
cc @adombeck @3v1n0 (you both touched the closely-related #1357 / #1359 / #1124).
Contributor guide
Research direction
Start in internal/brokers/manager.go, especially NewManager and AvailableBrokers, then trace the daemon configuration plumbing and existing broker tests. Add an opt-in setting that keeps the local broker registered but excludes it from the AvailableBrokers response; done means the configured picker omits local while internal local-broker consumers continue to work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- authentication, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100