WeblateOrg / WeblateOrg/weblate
SCIM 2.0 endpoint for automatic user and team provisioning and deprovisioning
- Dominant language
- Python
- Stars
- 6.1k
- Forks
- 1.4k
- Avg merge
- 9h 53m
- Merged PRs (30d)
- 395
Description
### Describe the problem
Organizations manage joiners and leavers in a directory service (Entra ID, Okta, Google Workspace). Weblate cannot consume that data today. Accounts can be provisioned via OAuth/OIDC/SAML just in time provisioning, but access and revoking of accounts needs to be managed manually:
- Onboarding: accounts and team memberships must be created by hand or by custom scripts against the REST API.
- Offboarding: nothing revokes access when a user leaves. Sessions, team memberships and API tokens stay valid until an admin notices.
SCIM 2.0 is the industry standard for this. Every major IdP can push user and group changes to a SCIM endpoint.
### Solution brainstorm
Add an optional SCIM 2.0 endpoint based on django-scim2 (https://github.com/15five/django-scim2).
I have a working prototype as a customization layer, about 350 lines (implementation + smoke tests), no changes to Weblate core. Verified against Weblate 2026.8.1:
- Users: create, filter (userName, externalId), GET, PUT, PATCH (active, displayName, emails), DELETE.
- Groups: map to Weblate teams by name. Add, remove and replace members
- Deactivation via `active=false` makes the user's API token return 401 and disables the user
- DELETE calls the existing `remove_user` anonymization.
Design points that need maintainer input before I open a PR, If it's interesting:
1. Where to store `externalId` - ID used to map the user created via SCIM to the internal user record: new fields on User/Group or separate link tables (prototype uses link tables).
2. Authentication for the endpoint: prototype accepts a Weblate API token of a user with `user.edit`.
3. DELETE semantics: anonymize vs deactivate -> I've opted for anonymize in my prototype
5. `REQUIRE_LOGIN` installs `LoginRequiredMiddleware`, so SCIM views need `login_not_required` wrappers to remain accessible and do its own API token auth.
### Describe alternatives you have considered
- SSO just-in-time provisioning: covers first login only. No team sync, no deprovisioning.
- External scripts against the REST API: every organization rebuilds the same sync, with polling delay and no standard IdP support.
- LDAP sync: only for LDAP shops and still no deprovisioning.
### Screenshots
_No response_
### Additional context
_No response_
Contributor guide
Research direction
Start by reviewing the proposed django-scim2 integration, the existing REST API authentication, and the prototype's smoke tests. Resolve the stated choices for externalId storage, endpoint authentication, DELETE behavior, and middleware handling; done means an agreed core design with coverage for user and group provisioning, synchronization, and deprovisioning.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- api, authentication, authorization, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100