SSO provider `name` silently acts as a persistent primary key — renaming it orphans all SSO accounts
- Dominant language
- JavaScript
- Stars
- 27
- Forks
- 7
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
The `name` field of each entry in `sso.js` (`list: [{ name: 'Keycloak', ... }]`) looks like a cosmetic label
The README only describes it as the text shown on the “Register with SSONAME” button. In reality it is also the **storage key of the SSO user database**: CryptPad core stores each SSO account's block seed under
```
data/sso_user///.json
```
(see `lib/storage/sso.js`, `userPathFromId()`), and the plugin resolves providers with a strict string match (`sso-utils.js`, `getProviderConfig`: `cfg.name === provider`).
If an admin ever changes `name` (rebranding the login button, fixing capitalization, migrating config to a new file/repo…), every SSO user lookup misses, and CryptPad **silently registers each returning user as a brand-new account** with a freshly generated seed (`SSOUtils.writeUser`). Users log in successfully via their IdP as usual, but land in an **empty drive**, with no error and no hint of what happened. Their data is still on the server, unreachable, under the old provider directory.
## Steps to reproduce
1. Configure an OIDC provider in `sso.js` with `name: 'keycloak interhop'`.
2. Register a user through SSO, put documents in the drive.
3. Change the provider to `name: 'Keycloak'` (same `url`, `client_id`, everything else identical).
4. Restart, log in again with the same IdP user.
**Expected:** either the same account, or a clear error explaining the provider is unknown.
**Actual:** authentication succeeds and a new, empty account is silently created (`data/sso_user/Keycloak/...` next to the orphaned `data/sso_user/keycloak interhop/...`). The user's public key changes; drive, teams and contacts appear lost.
## Suggested fix
**Decouple the stable identifier from the display label** (backward compatible):
- Add an immutable `id` field per provider, and demote `name` to a pure display label that admins can change freely.
- Resolve providers and build storage paths with `cfg.id || cfg.name`: existing instances keep working unchanged (their `sso_user//` directories remain valid), while new installations are encouraged to set a short stable `id` (e.g. `keycloak`) separate from the button text (e.g. `Sign in with MyOrg`).
- The decree-based admin UI already asks for a “provider id”; it only lacks the separate label field.
## Complementary guard rails (each valuable on its own)
1. **Startup / `/checkup` warning:** if `data/sso_user/` contains provider directories that don't match any configured provider, log a prominent warning — e.g. “N SSO accounts exist for provider ‘keycloak interhop’ which is no longer configured” — and surface it in the admin panel.
2. **Explicit confirmation on SSO registration:** before creating a brand-new account for a returning IdP identity, show “No existing account found for this identity — create a new one?” instead of registering silently. A user who knows they already have an account would stop right there.
3. **Documentation:** state in the plugin README and in `sso.example.js` that the provider identifier is persistent, keyed into the account database, and must never change once users have registered.
4. **Repair tool:** an admin CLI/panel action “rename provider” that moves `sso_user//` (and associated `sso_block` entries) to the new identifier, turning this incident from apparent data loss into a documented maintenance operation.
## Context
Hit this in production while migrating a Docker deployment to a new config repository: the new `sso.js` was rewritten from the example and the provider name changed from `keycloak interhop` to `Keycloak`. Same Keycloak realm and client, same nginx — yet every user came back to an empty drive. Recovery was easy once diagnosed (restore the exact old `name` and restart), but the failure mode is invisible and looks like total data loss.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with lib/storage/sso.js and its userPathFromId() logic, then trace provider lookup in sso-utils.js through getProviderConfig and SSOUtils.writeUser. Compare how the configured name is used for identity resolution and storage, and decide the compatible scope for separating a stable provider identifier from its display label. Done should prevent renamed providers from silently creating empty accounts while preserving existing account paths.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- authentication, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100