User Provisioning Guide
Conceptual guide covering how user provisioning works in the Calimatic Auth platform, the three provisioning methods, organization membership, auto-licensing, and password handling.
Prerequisites
- Familiarity with the Calimatic Auth platform concepts (organizations, roles, app clients)
- For API-based provisioning: a registered app client or API key with
org:users:managepermission - For organization provisioning:
org:managepermission on the app client or API key
Overview
User provisioning is the process of creating user accounts, assigning them to organizations, granting app licenses, and setting up their credentials. The Calimatic Auth platform provides three methods for provisioning users, each suited to different use cases.
+-----------------+
| User Provisioned |
+-----------------+
|
+---------------+---------------+
| | |
Admin UI API Call SCIM Sync
(manual) (programmatic) (automated)
| | |
v v v
+------------------------------------------+
| Keycloak (Identity Store) |
+------------------------------------------+
| | |
v v v
+------------------------------------------+
| Platform DB (Org, Roles, Licenses) |
+------------------------------------------+
The Three Provisioning Methods
1. Admin UI
Manual provisioning through the Calimatic Auth admin dashboard.
Best for: One-off user creation, small teams, initial setup.
How it works:
- Admin navigates to Admin > Users > Create User or Invite User
- Fills in email, name, role, and selects apps to assign
- User is created in Keycloak and the platform database simultaneously
- An invitation email is sent with a link to set their password
Capabilities:
- Create individual users
- Invite users to organizations
- Assign roles and app licenses
- Set temporary passwords
- Suspend, deactivate, or reactivate users
2. API (Provisioning API)
Programmatic provisioning via HTTP API calls.
Best for: Application-initiated user creation, bulk imports, migration, automation scripts.
Key endpoints:
| Endpoint | Use Case |
|---|---|
POST /api/v1/organizations | Create an organization (apps must create orgs first) |
GET /api/v1/organizations?slug=<slug> | Look up an organization by slug |
POST /api/v1/users/provision | Create or provision a single user |
POST /api/v1/users/provision/bulk | Bulk provision up to 500 users |
POST /api/v1/users/import | Import existing users (migration-friendly defaults) |
Authentication methods:
- App client credentials (
x-client-id+x-client-secret) -- for app-initiated provisioning - API key (
x-api-key) -- for server-to-server automation - Session -- for internal tools using the admin's session
For detailed API documentation, see the User Management API Reference.
3. SCIM (System for Cross-domain Identity Management)
Automated provisioning via the SCIM 2.0 protocol, driven by an external identity provider.
Best for: Enterprise customers using Azure AD, Okta, OneLogin, or other identity providers that support SCIM.
How it works:
- The enterprise customer configures their IdP to point to the Calimatic SCIM endpoint
- When users are assigned to the Calimatic app in the IdP, they are automatically created
- When users are unassigned or removed, they are automatically deactivated
- Profile changes in the IdP are synced to Calimatic Auth
For SCIM endpoint documentation, see the SCIM API Reference.
How Provisioning Works Internally
Regardless of the method used, every user provisioning operation follows the same internal flow:
Step 0: Organization Creation (Required First)
Organizations must exist on the auth platform before users can be provisioned into them. Organizations originate at the app level -- when a customer subscribes to an app, the app creates the org on the auth platform.
API endpoint: POST /api/v1/organizations
{
"name": "Acme Corp",
"slug": "acme-corp",
"type": "customer"
}
When called by an app client, the calling app is automatically enabled for the new organization. The endpoint is idempotent -- if the slug already exists, it returns the existing org with a 409 status.
This step is a prerequisite for all user provisioning. The provisioning API will return a 404 ORG_NOT_FOUND error if you try to provision a user into a non-existent organization.
Step 1: Keycloak User Creation
The user is created in Keycloak (the identity store). Keycloak handles:
- Credential storage (passwords, social login links)
- Email verification
- Required actions (UPDATE_PASSWORD, VERIFY_EMAIL)
- Authentication flows
If the user already exists in Keycloak (matched by email), the existing Keycloak account is reused.
Step 2: Platform Identity Creation
A user_identities record is created in the platform database. This record stores:
- Platform-specific profile data (display name, avatar, phone, timezone, locale)
- Organization memberships
- User type (customer_admin, customer_teacher, etc.)
- Status (active, suspended, deactivated)
- Source tracking (how the user was created)
- External IDs for cross-referencing with other systems
Step 3: Organization Membership
If an organization is specified, the user is added as a member:
- A membership entry is added to
organizationMemberships(JSONB array on the identity) - The specified role (or
memberby default) is assigned - If the user has no primary organization, the specified org becomes their primary
Step 4: App License Assignment
App licenses are assigned based on the request:
- If the caller is an app client, the calling app's license is auto-included
- If specific apps are requested, only enabled apps on the org are assigned
- If no apps are specified and no app client context exists, all enabled org apps are assigned
- Licenses are recorded in the
user_app_licensestable
Step 5: Email / Notification
Depending on configuration:
- Invite email (
sendInviteEmail: true): A password setup email is sent with a 72-hour expiry link - Temporary password (
temporaryPassword): The password is set in Keycloak with the UPDATE_PASSWORD required action - No action: User account is created but no notification is sent (common for migration)
Step 6: Audit and Webhooks
- An audit log entry is created (
USER_CREATEDevent type) - A
user.createdwebhook event is dispatched to all subscribed webhooks
Auto-Licensing Behavior
The platform follows a three-layer licensing model inspired by Okta:
Layer 1: App Registration
The app is registered as an OAuth client with the platform.
(admin creates via POST /api/v1/admin/app-clients, or dynamic registration)
Layer 2: Org Enablement
The app is enabled for a specific organization.
(organization_app_access record with isEnabled: true)
Layer 3: User Assignment
Individual users are granted a license for the app.
(user_app_licenses record)
Auto-Assignment Rules
| Scenario | Behavior |
|---|---|
| App client provisions a user | Calling app's license is automatically assigned |
Explicit applications array provided | Only those apps (if enabled on org) are assigned |
| No apps specified, no app client context | All enabled org apps are assigned |
| App not enabled on org | Silently filtered out (no error) |
Example
A Partners Portal app client (application: "partners") invites a user to an organization that has three enabled apps: edtech, partners, and scheduler.
- The user automatically gets a
partnerslicense (calling app) - If the request includes
applications: ["edtech"], the user also getsedtech - If no
applicationsarray is provided, the user getspartnersonly (from the app client context)
Organization Membership Model
Users can belong to multiple organizations simultaneously. This supports:
- Consultants managing multiple schools
- Internal employees with cross-org access
- Users transitioning between organizations
Membership Structure
Each membership is stored as a JSONB entry:
{
"organization_id": "uuid-of-org",
"role": "admin",
"permissions": [],
"joined_at": "2025-01-15T10:00:00.000Z"
}
Primary Organization
Each user has a primaryOrganizationId that determines:
- Default organization context in OIDC claims
- Which organization's branding they see on login
- The default org used when no explicit org is provided in API calls
The first organization a user is added to becomes their primary. This can be changed later.
Adding to Additional Organizations
When a user is provisioned for an organization they already exist in, the provisioning system:
- Checks if the user is already a member of the target org
- If not, adds a new membership entry
- Assigns app licenses for the new org
- Does not change the user's primary org (unless they had none)
Password Handling
The platform supports multiple password strategies depending on the use case:
Invite Email (Default)
When sendInviteEmail: true (the default for single provisioning):
- The user is created in Keycloak with
VERIFY_EMAILandUPDATE_PASSWORDrequired actions - A platform-managed invite email is sent with a secure link
- The link directs the user to a password setup page
- The link expires after 72 hours
- After setting their password, the user can log in normally
Temporary Password
When temporaryPassword is provided:
- The password is set in Keycloak as a temporary credential
- Keycloak adds the
UPDATE_PASSWORDrequired action - On first login, the user is prompted to choose a new password
- No invite email is sent (unless
sendInviteEmailis alsotrue)
Password Hash Migration (Seamless)
When passwordHash is provided:
- The bcrypt or PBKDF2 hash is stored directly in the platform database
- No invite email is sent -- the user is ready to log in immediately
- No password reset is required
- For PBKDF2 hashes, automatic upgrade to bcrypt happens on first successful login
- This is the recommended approach for migrating existing users from apps that use compatible password hashing
{
"email": "jane@example.com",
"firstName": "Jane",
"lastName": "Smith",
"passwordHash": "$2b$12$...",
"sendInviteEmail": false
}
Supported formats:
- bcrypt (
$2b$,$2a$) -- stored as-is, verified directly - PBKDF2 (Keycloak JSON format) -- transparently upgraded to bcrypt on login
SSO (No Password)
When the organization has SSO configured (Google Workspace, Microsoft 365, SAML, OIDC):
- Users do not need a password at all
- They authenticate via their organization's identity provider
- The platform detects the SSO configuration and redirects accordingly
- This is the preferred approach for enterprise customers
Password Reset
For users who need to reset their password after initial setup:
POST /api/v1/users/{id}/reset-passwordsends a Keycloak-managed password reset emailPOST /api/v1/users/{id}/set-passwordsets a new temporary password directly
Password Requirements
The platform enforces Keycloak's password policy for the calimatic-customers realm:
- Minimum 8 characters
- At least 1 digit
For the calimatic-internal realm (internal employees):
- Minimum 12 characters
- At least 1 uppercase, 1 lowercase, 1 digit, 1 special character
- Cannot be the same as the last 5 passwords
- Cannot contain the username
Provisioning Across the Four App Categories
Category 1: New Calimatic Apps
- Create your organization via
POST /api/v1/organizationsfirst - Use the Provisioning API to create users
- App client auto-licensing handles license assignment
- Send invite emails for new users
- See New Calimatic App Guide
Category 2: Existing Calimatic Apps
- Use the Import API for bulk migration
- Set
sendInviteEmails: falseandskipExisting: true - Migrate password hashes directly via
passwordHashfor seamless login, or use reset emails as a fallback - See Migrating Calimatic App Guide
Category 3: New Third-Party Apps
- Use the Provisioning API for creating users in Calimatic orgs
- Set up webhooks to receive user lifecycle events
- Consider SCIM for enterprise customer provisioning
- See Integrate Third-Party Guide
Category 4: Existing Third-Party Apps
- Use the Import API to bring existing users into Calimatic Auth
- Create organizations on the auth platform via
POST /api/v1/organizations - Preserve external IDs for cross-referencing (
externalIdfield) - Set up webhooks for ongoing sync
- See Migrate Existing Users Guide
Deduplication
The provisioning system deduplicates by email address:
- Email addresses are normalized (lowercased, trimmed) before comparison
- If a user with the same email exists in the platform database, the existing user is returned/updated
- If a user with the same email exists in Keycloak but not in the platform database, the Keycloak account is linked
This ensures that users who exist across multiple organizations or apps always have a single identity.
Webhook Events
All provisioning operations dispatch webhook events:
| Operation | Event |
|---|---|
| User created | user.created |
| User updated (added to org) | user.updated |
| Bulk import completed | user.created (per user) |
| Password reset triggered | user.password_reset |
| Temporary password set | user.password_reset |
See the Webhooks API Reference for details on subscribing to events.
Related Documentation
- User Management API Reference -- Full endpoint documentation
- Webhooks API Reference -- Event subscriptions and delivery
- SCIM API Reference -- Automated enterprise provisioning
- New Calimatic App -- Quick start for Category 1
- Migrating Calimatic App -- Migration runbook for Category 2
- Integrate Third-Party -- OIDC setup for Category 3
- Migrate Existing Users -- Import guide for Category 4