Provisioning with SCIM.
SCIM 2.0Keep an app's users in sync with your identity provider. When someone joins, they're provisioned automatically; when they leave, deprovisioning disables the account and cuts every live session — no manual cleanup, no lingering access.
Turn it on
Mint a provisioning token — from the app's Provisioning tab in the dashboard, or the CLI. The token is shown once; store it in your IdP.
tilldev auth scim <app> rotate
# → scim_base_url https://auth.tilldev.dev/scim/v2/apps/<public_id>
# bearer token scim_… (shown once)Rotating again replaces the token (the old one stops working). Turn SCIM off with tilldev auth scim <app> disable.
Configure your IdP
In Okta, Microsoft Entra ID, or any SCIM 2.0 client, add a provisioning integration with:
| Field | Value |
|---|---|
| SCIM base URL | https://auth.tilldev.dev/scim/v2/apps/<public_id> |
| Authentication | HTTP Header — Authorization: Bearer <token> |
| Unique identifier | userName (TillAuth uses the email as the userName) |
Discovery endpoints (/ServiceProviderConfig, /ResourceTypes, /Schemas) live under the same base URL, so most IdPs auto-detect what's supported.
Supported operations
TillAuth implements the SCIM Users resource:
| Operation | Effect |
|---|---|
POST /Users | Provision a new user. The email is treated as verified. A password — or a pre-computed password_hash (see Migration below) — may be supplied. |
GET /Users?filter=… | List / look up. Supports userName eq "…". |
GET /Users/{id} | Fetch a single user. |
PUT /Users/{id} | Replace name / active state. |
PATCH /Users/{id} | Partial update — most importantly active: false. |
DELETE /Users/{id} | Deprovision the user. |
Bring an existing user base — passwords included
Moving off another stack? You don't have to force password resets. TillAuth accepts your legacy password hashes verbatim — bcrypt ($2a$/$2b$/$2y$) and pbkdf2 in its passlib/PHC ($pbkdf2-sha256$…) or Django (pbkdf2_sha256$…) renderings — verifies against them on sign-in, and transparently re-hashes each user to Argon2id the first time they sign in successfully. Zero resets, and no plaintext password ever crosses the wire.
For bulk moves, use the import endpoint (same bearer token as SCIM, up to 500 users per call). Each row reports its own outcome — created, revived, conflict (a live user with that email already exists and is never touched), invalid, or error — so a partial failure never rolls back the rest:
POST https://auth.tilldev.dev/admin/apps/<public_id>/users/import
Authorization: Bearer <token>
Content-Type: application/json
{ "users": [
{ "email": "ada@example.com",
"display_name": "Ada Lovelace",
"password_hash": "$pbkdf2-sha256$29000$mJPy…$oQ8T…" },
{ "email": "no-password@example.com" }
] }password_hash and let them set a password via reset or magic link. Every import is audit-logged, per batch and per user.Deprovisioning
Deprovisioning is the point of SCIM. When your IdP marks a user inactive — a PATCH setting active: false, or a DELETE — TillAuth:
- disables the account, so no new sign-in of any kind succeeds; and
- revokes every one of that user's live sessions, so tokens already in flight stop being accepted shortly after.
PATCH https://auth.tilldev.dev/scim/v2/apps/<public_id>/Users/<id>
Authorization: Bearer <token>
Content-Type: application/scim+json
{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{ "op": "replace", "path": "active", "value": false }] }active: true) restores their ability to sign in, but does not resurrect old sessions — they sign in fresh.Related: Sign in with TillAuth (OIDC) · Sessions · Audit log records every provisioning event.