Skip to main content

SCIM user provisioning

Your workspace speaks SCIM 2.0 (RFC 7643 and 7644) so your identity provider (IdP) can push user lifecycle events straight into OnTrackio: a new hire appears the moment HR adds them upstream, role and department changes flow within minutes, and a departure deactivates the account automatically. This guide wires up Okta or Microsoft Entra.

:::note Before you begin

  • You're an administrator on the workspace. Minting the token and mapping groups both require an admin role.
  • You're working against your own tenant subdomain — <slug>.app.ontrackio.com. SCIM is per-tenant; the central app.ontrackio.com host has no SCIM surface.
  • You have admin access to one IdP — Okta or Microsoft Entra — and the rights to add a provisioning app there.
  • Connect one IdP per workspace. See One IdP per workspace before you wire a second. :::

How provisioning maps to the lifecycle

SCIM events from your IdP drive three flows in OnTrackio.

Lifecycle eventSCIM operationWhat happens in OnTrackio
JoinerPOST /UsersA user is created. IT can pre-assign hardware and license seats before day 1.
MoverPATCH /Users/{id}Department, job title, and manager update. Cost-allocation reports stay accurate.
LeaverPATCH /Users/{id} with active: falseThe account is deactivated, the hardware-return workflow fires, and seats are flagged for reclamation. The audit log records the timestamp.

What the SCIM API exposes

The endpoints below are reached at https://<slug>.app.ontrackio.com/scim/v2. Your IdP appends the resource paths itself, so you only ever paste the base URL.

ResourceVerbsPurpose
/ServiceProviderConfigGETCapability discovery
/Schemas, /Schemas/{id}GETUser and group schemas
/ResourceTypes, /ResourceTypes/{name}GETAdvertises Users and Groups support
/UsersGET, POSTList (paginated, filterable); create a joiner
/Users/{id}GET, PUT, PATCH, DELETERead; full replace; partial update (mover, leaver); soft-delete
/GroupsGET, POSTList (filterable); create a group with members
/Groups/{id}GET, PUT, PATCH, DELETERead; replace members; add or remove members and rename; soft-delete
note

Every request authenticates with a Bearer token — no session cookies, no CSRF token. Responses use Content-Type: application/scim+json.

Step 1 — mint a SCIM token

The token is the credential your IdP uses to authenticate. Mint it in OnTrackio first, then paste it into the IdP in step 2.

  1. In the Admin console, open /admin/api-tokens (also linked from Settings → API & webhooks). The page is titled API tokens.
  2. In the Mint new token card, set Token name to something that records which IdP it's for — for example scim-okta or scim-entra.
  3. Set Owner to a service-account user, or yourself for testing. When the owner's account is deactivated the token stops working, so pick someone you'll keep active.
  4. Under Abilities (scope), tick only SCIM 2.0 endpoints (IdP joiner/mover/leaver push). Granting nothing else keeps the token least-privileged.
  5. Set Expires at (optional but recommended) to a date within a year, and plan to rotate it annually.
  6. Optionally, paste your IdP's egress CIDR ranges into IP allowlist (CIDR, optional). A request from any other address gets a 401 with no hint that the token was valid.
  7. Select Mint token.

The plaintext token appears once in a green banner — This is the only chance to copy the plaintext. We store only the SHA-256 hash; refreshing this page will hide it. Select Copy and hold it for step 2. The IdP sends it as Authorization: Bearer <token>.

warning

The plaintext is shown once and is never recoverable. If you lose it, revoke the token and mint a new one.

Step 2a — connect Okta

If you already have an Okta app for OnTrackio (the same tile users sign in through), add SCIM provisioning to that app so users see one tile and assignment lists line up. If you're SCIM-only, use the standalone SCIM 2.0 Test App (OAuth Bearer Token) template from the App Catalog instead — the steps from the connector panel onward are the same.

  1. Open your OnTrackio app in Okta admin (Applications → Applications, then select the tile).

  2. In General → App Settings → Edit, under Provisioning choose the SCIM radio, then select Save. A new Provisioning tab appears in the app.

  3. On the Provisioning tab, go to Settings → Integration → Edit on the SCIM Connection panel and fill in the fields below.

    FieldValue
    SCIM connector base URLhttps://<slug>.app.ontrackio.com/scim/v2
    Unique identifier field for usersuserName
    Supported provisioning actionsTick Import New Users, Push New Users, Push Profile Updates. Leave the group options unticked.
    Authentication ModeHTTP Header
    AuthorizationThe plaintext token from step 1. Okta prepends Bearer for you.
  4. Select Test Connector Configuration. Expect green ticks next to User Import, Import Profile Updates, Create Users, and Update User Attributes, and red marks next to Push Groups and Import Groups — OnTrackio doesn't accept group push from Okta, so that's correct.

  5. Select Save.

  6. Go to Provisioning → To App → Edit and enable the actions that drive each flow.

    ActionFlowSCIM call
    Create UsersJoinerPOST /Users
    Update User AttributesMoverPATCH /Users/{id}
    Deactivate UsersLeaverPATCH /Users/{id} with active: false
    Sync PasswordLeave off — OnTrackio is SSO-only and never accepts passwords over SCIM.
  7. Under Provisioning → To App → Attribute Mappings, map Okta profile attributes to OnTrackio's SCIM attributes.

    OktaOnTrackio (SCIM)
    user.emailuserName and emails[type eq "work"].value
    user.profile.firstNamename.givenName
    user.profile.lastNamename.familyName
    user.titletitle
    user.departmenturn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department
    user.employeeNumberexternalId and enterprise:User:employeeNumber
    user.managerenterprise:User:manager.value
  8. On the Assignments tab, assign your test user. If you assigned the user before enabling SCIM, select Provision User from the row's menu to force the first push — Okta only auto-pushes assignments made after SCIM is wired.

tip

Use user.profile.firstName and user.profile.lastName, not the shorter user.firstName / user.lastName. Okta's expression validator rejects the short forms with Invalid property firstName in expression.

Step 2b — connect Microsoft Entra

  1. In Microsoft Entra admin → Enterprise applications → New application → Create your own application, name it something like OnTrackio ITAM (SCIM).

  2. In the app's Provisioning pane, set Provisioning Mode to Automatic.

  3. Fill in Admin Credentials.

    FieldValue
    Tenant URLhttps://<slug>.app.ontrackio.com/scim/v2
    Secret TokenThe plaintext token from step 1
  4. Select Test Connection. Entra calls /ServiceProviderConfig and a probe filter on /Users to verify the credentials.

  5. Under Mappings → Provision Microsoft Entra ID Users, map the attributes below.

    Entra sourceOnTrackio target
    userPrincipalNameuserName
    Switch([IsSoftDeleted], , "False", "True", "True", "False")active
    givenNamename.givenName
    surnamename.familyName
    displayNamedisplayName
    mailemails[type eq "work"].value
    employeeIdexternalId
    jobTitletitle
    departmenturn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department
    managerenterprise:User:manager.value
  6. Select Start provisioning. Entra's first cycle reads the current OnTrackio directory; later cycles reconcile roughly every 40 minutes.

How groups map to roles

OnTrackio stores SCIM groups and their members as a first-class concept, but a SCIM group is metadata, not a permission grant. Adding a user to a SCIM group named admin does not give them the OnTrackio admin role. This is a deliberate safeguard: without it, your IdP could grant super-admin to anyone by editing group membership, bypassing admin review.

To turn IdP group membership into OnTrackio roles, map the groups explicitly.

  1. In the Admin console, go to Settings → Integrations and open the SCIM 2.0 Provisioning card (or open /admin/scim/role-mappings).
  2. In the Add mapping card, pick a SCIM group and the OnTrackio role to grant.
  3. Select Add mapping.
BehaviourDetail
Apply on saveAdding a mapping immediately grants the role to every current member of the SCIM group.
Apply on churnWhen the IdP later adds members over SCIM, the grant applies automatically.
Revoke on removalRemoving a member from a mapped group revokes the role — but only for grants that came from SCIM.
Manual grants winA role you assign on the Users page is marked manual and survives SCIM churn. Re-saving a user "locks" their roles this way.
Unmapped groupsAn unmapped SCIM group grants nothing — there are no implicit role grants from an IdP-named group.
note

SCIM groups are still useful beyond roles: reporting filters ("hardware assigned to the Sales group"), team-based automation, and reconciliation ("who's in this IdP group that OnTrackio thinks isn't?").

Filtering and pagination

Your IdP reads the directory with SCIM filters and a cursor. You rarely write these by hand, but the supported set determines what an IdP can ask for.

The full RFC 7644 operator set works on Users: eq, ne, co, sw, ew, pr, the ordering operators gt / lt / ge / le, the combinators and / or / not, and parentheses for grouping. For example, userName co "alice" and active eq true.

ResourceFilterable attributes
UsersuserName, email, externalId, active, displayName, title, name.givenName, name.familyName, name.formatted
GroupsdisplayName eq, externalId eq, displayName co only

A filter on an attribute outside these lists returns 400 with scimType: invalidFilter.

Listings paginate with a standard cursor — GET /scim/v2/Users?startIndex=1&count=100. startIndex is 1-indexed, count defaults to 100 and caps at 200, and the response carries totalResults, startIndex, itemsPerPage, and Resources. If an IdP isn't paginating a large directory, enable paging on its side — a single unpaged request over thousands of users can time out.

How deactivation and deletion behave

OperationEffect
PATCH active: false (leaver)The account flips to inactive and an audit-log entry records the IdP-initiated deactivation with its timestamp.
DELETE /Users/{id}A soft delete. The user drops out of listings (a later GET returns 404), but the row is retained so hardware assignments, audit history, and GDPR records keep their references.
Re-provision after deleteA POST for a soft-deleted user restores and updates the record and returns 200, so a re-hire reuses the same identity.
note

To erase a user's personal data entirely, use the GDPR erasure flow in the admin UI rather than SCIM DELETE. SCIM DELETE is intentionally reversible. See GDPR data subject requests.

One IdP per workspace

Connect only one IdP to a workspace's SCIM endpoint at a time. SCIM resource IDs are owned by whichever IdP first provisions a user, and each IdP caches its own mapping of its users to those IDs. If both Okta and Entra push to the same workspace, one can silently overwrite the other's records when an ID is reused. The symptom is a user's userName, name, or externalId appearing to change between cycles even though no admin touched them.

To migrate from one IdP to another, cut over in a window rather than running both:

  1. Turn provisioning off on the old IdP.
  2. Wait one full sync cycle (about 40 minutes) so in-flight writes drain.
  3. Turn provisioning on on the new IdP.
  4. Confirm on /scim/v2/Users that every expected user is present with the correct externalId.
  5. Remove the old IdP's SCIM app once you trust the new one's coverage.

If you genuinely need two IdPs writing at once — usually a merger scenario — contact support. The supported path is a per-IdP workspace, or an identity hub (Okta Inbound Federation, Microsoft Cross-Tenant Sync) fanning out to one SCIM endpoint with consistent IDs.

Why some attributes are off-limits

OnTrackio's user schema deliberately omits roles, entitlements, and groups as writable user attributes, and the service config doesn't advertise password change. Each omission closes a path that would let an IdP unilaterally grant a role or push a password. Role assignment stays in the admin UI or SAML role-mapping; passwords never travel over SCIM. PATCH paths the product doesn't store (such as preferredLanguage or locale) are accepted and silently ignored rather than rejected, so a long tail of optional IdP attributes doesn't pause provisioning.

Troubleshooting

SymptomWhat to do
Test connection fails with 401The token expired, was revoked, or its owner was deactivated — mint a fresh one. Check the header is Authorization: Bearer <token> with no extra whitespace. If you set an IP allowlist, confirm the IdP's egress IP is in it (it appears in the admin activity log around the failed attempt).
Test connection fails with 404The base URL is wrong. It must end in /scim/v2 — no trailing slash, no /Users suffix. It must use your tenant subdomain, not the central app.ontrackio.com host.
Schema mismatch or attribute not foundThe IdP is requesting an attribute OnTrackio doesn't advertise — commonly groups, roles, entitlements, or addresses. Check GET /scim/v2/Schemas and remove the mapping.
Provisioning paused after the first cycleOkta and Entra both pause on repeated failures. Fix the root cause (usually a 401 or a malformed filter), then resume provisioning in the IdP.
Filter rejected with invalidFilterThe filter uses an unsupported operator or attribute. Switch to a supported one from the tables above.
A user's details change between cycles on their ownTwo IdPs are pushing to the same workspace. See One IdP per workspace.