painfree 0.2.3
Three findings from a production deployment against an organisation-wide Keycloak realm, all about the gap between what an identity provider sends and what this service should be willing to keep.
A token carrying no roles at all was silent — and it is Keycloak's default. Browser sessions are established from the id_token, and Keycloak's built-in realm-roles mapper ships with "Add to ID token" off. So on a default realm a correctly assigned administrator signs in successfully, holding nothing, and the console is empty with no line to read. auth.no_roles_in_token now warns, quotes the configured claim path back so it can be compared against the mapper, and distinguishes an absent claim from an empty one.
Every provider role was persisted and logged, not just the ones that mean something. One sign-in on that realm carried 34 role names, of which painfree understands two — and all 34 went into the session row and onto the audit row that a deployment deliberately never prunes. A service whose purpose is custody of bank keys should not also become the archive of an organisation's authorization model. The intersection now happens once, at the door: only the names this deployment maps are kept anywhere, and the remainder survives as a count. Privilege is unaffected — an administrator name is one this deployment maps by definition.
That also makes the diagnostic worth reading again. auth.unmapped_roles is info with a count when recognised names travelled alongside others (a shared realm, the ordinary case) and warning only when none of what arrived was ours — which is the case that actually indicates a misconfigured role name.
The recovery page gave host paths with no host. Two relative paths, on a page reached in a browser, in a deployment that is containerised by definition — and the process serving that page is refused the custody secret, so the reader's first instinct fails in a way that looks like the file is missing. The page and the downloadable card now name the anchor (the directory holding compose.yaml, on the host), mark the command as a host shell command, and give the custody boundary as the reason rather than leaving it to be discovered.
production.env.example documents that roles must reach the id_token, and describes the client-role mapper that keeps an organisation's other role names at the provider entirely.
Upgrading: nothing to do. Existing sessions and audit rows are untouched; new ones carry only the names this deployment maps. If you set PAINFREE_OIDC_MEMBER_ROLE, note it now decides what is kept as well as what is not warned about — a member name belongs in it.