|
|
4 days ago | |
|---|---|---|
| .. | ||
| README.md | 4 days ago | |
| design.md | 4 days ago | |
README.md
SCIM v2 provisioning
This fork adds a SCIM v2 provisioning server (RFC 7643 / RFC 7644) so organization membership can be driven from an identity provider. Microsoft Entra ID is the tested IdP. Design details and diagrams: design.md.
What it does, honestly
- Automated invite: assigning a user in the IdP creates the Vaultwarden account (if needed) and org membership, and sends the invite email.
- Automated deprovision: removing a user (or setting
active: false) revokes org access immediately. Restore is lossless. - Group sync: group existence and membership, when
ORG_GROUPS_ENABLED=true. - Not automated: the final Confirm step. End-to-end encryption means the org key must be wrapped for each member by an admin's client; no server can do it. Provisioned users wait in Invited / Accepted until an admin confirms them in the web vault. See design.md for why this is a property of the encryption model, not a missing feature.
Server setup
-
Enable SCIM in the server config (default is off):
SCIM_ENABLED=true # optional tuning SCIM_RATELIMIT_SECONDS=1 SCIM_RATELIMIT_MAX_BURST=60 -
Generate the per-organization SCIM token (requires an org admin session; re-authenticates with your master password like API key rotation):
curl -s -X POST "$DOMAIN/api/organizations/$ORG_ID/scim/api-key" \ -H "Authorization: Bearer $ADMIN_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"masterPasswordHash": "..."}'The response contains the token (
scim_v1.<org>.<secret>) and the tenant URL. The token is shown exactly once; only its sha256 digest is stored. POST again to rotate (the old token stops working immediately), DELETE the same path to disable SCIM for the org, GET/scim/statusto inspect. -
TLS is required in front of the server (Entra refuses plain http). If a reverse proxy sets client IPs, make sure it overwrites the
IP_HEADERheader (defaultX-Real-IP); the SCIM rate limiter keys on that value.
Entra ID setup
-
Entra admin center: Enterprise applications > New application > Create your own application (non-gallery).
-
Provisioning > Automatic:
- Tenant URL:
https://<your-domain>/scim/v2/<org_id> - Secret Token: the
scim_v1...value from step 2 above. - Test Connection, then Save.
- Tenant URL:
-
Attribute mappings (Users):
Entra attribute SCIM attribute Vaultwarden userPrincipalName (or mail) userNameaccount email (lowercased) objectId externalIdmembership external id Switch([IsSoftDeleted], , "False", "True", "True", "False") activerevoke / restore displayName displayNameaccount name (set at creation only) Map
userNamefrom mail rather than userPrincipalName if your UPNs are not routable mailboxes: the value must be a deliverable email address, because it becomes the Vaultwarden login and receives the invite.Recommended: delete the default mappings this server does not sync (
roles,preferredLanguage,title, addresses, phones). They are accepted and ignored, but trimming them keeps the Entra sync log clean. -
Groups: map
displayNameandobjectIdtoexternalId. Members sync as diffs. Assign users before (or together with) their groups; a group member who is not yet provisioned as a user is rejected until the user sync runs. -
Assign users/groups to the app and start provisioning. Entra's initial cycle lists existing users first (
userName eqfilters), then creates.
Behaviour notes and deviations
- DELETE = revoke. Both Entra soft delete (
active: false) and hard DELETE revoke the membership. The row and its keys survive, so restoring a returning user needs no re-confirmation. No destructive operation is exposed to the IdP at all. This is a deliberate deviation from RFC 7644. - Roles are not synced. Everyone provisions as the User role; promote people in the web vault. Vaultwarden's Custom role cannot round-trip through SCIM.
- userName / displayName changes are not synced after creation. The email is the login identity; the display name belongs to the person globally, not to one org's directory. Renames in Entra succeed (accepted and ignored) rather than erroring the sync.
- SCIM user id is the org membership id, not the account id. The same person in two orgs has two SCIM ids: SCIM is org-scoped by construction.
- Every SCIM change is written to the org event log (admin-visible) with the
synthetic actor
vaultwarden-scim-...whenORG_EVENTS_ENABLED=true.
Operational lifecycle
- Entra assigns user, SCIM creates membership at Invited, invite mail sent.
- User clicks the invite, creates or logs into their account (Accepted).
- An org admin confirms the member in the web vault (Confirmed). This is the manual step; the admin's client wraps the org key for the member.
- Entra unassigns or soft deletes, SCIM revokes immediately. Vault access stops on the member's next sync.
- Re-assignment restores the membership exactly as it was, including the confirmed state, with no new invite or confirmation needed.