Automatic provisioning with SCIM 2.0 Module

Vaks PM · Integration guide · SCIM 2.0 · July 2026

What you will end up with. Your directory creating, updating and deactivating Vaks PM accounts on its own, and keeping teams in step with directory groups — so joiners, movers and leavers are handled where you already handle them. This guide covers Microsoft Entra ID and Okta.
Set up single sign-on first. Both sides key accounts on the directory's immutable object identifier. Configure and test OIDC or SAML with a pilot user before switching provisioning on, so you find out then rather than at scale that the identifier lines up. Accounts provisioned by SCIM are sign-on only — they have no password, so without working federation nobody can use them.

What it does — and what it does not

Vaks PM exposes a standard SCIM 2.0 endpoint that your directory drives. It supports users and groups, with full create, read, update, patch and delete. There is no scheduler on the Vaks PM side: every change is pushed by your directory on its own cycle, typically every 40 minutes for Entra.

Provisioning and licence seats

This is the single most surprising behaviour, so it is worth stating plainly before you start.

SCIM never grants a licence seat. A provisioned user has an account but no dashboard access until a seat is granted. This is deliberate: your directory can push a thousand people without silently consuming a thousand licences, and provisioning never fails with a quota error. But it means that, left alone, newly provisioned users sign in to nothing.

You have two ways to close that gap:

Prerequisites

SideWhat you need
DirectoryRights to configure provisioning on an enterprise application. In Entra this needs an Entra ID P1 or P2 licence; automatic provisioning is not available on the free tier.
Vaks PMThe org:manage permission — an organization administrator.
LicenceA licence covering the SCIM feature. Without it the endpoint refuses every call and the token buttons are hidden.
Single sign-onConfigured and tested, per the warning above.
Google Workspace cannot drive this. Its outbound provisioning is restricted to applications in Google's own catalog and offers no custom SCIM configuration, so it cannot provision a self-hosted application. With Google Workspace, use SAML single sign-on with automatic account creation on first sign-in, and manage leavers by suspending the Google account — federated sign-in stops immediately, though the Vaks PM account stays active until someone deactivates it. If you need true lifecycle automation, an intermediary identity provider that does support outbound SCIM is the usual answer.

Step 1 — Generate the token in Vaks PM

Open Admin → Integrations → Single sign-on and find the SCIM provisioning card below the provider list. It gives you the two values your directory needs.

Tenant URL — click to copy:

https://<your-host>/api/v1/scim/v2

Secret token — press Generate SCIM token. The secret is displayed once, under the notice "Copy this token now — it won't be shown again." Paste it straight into your directory.

The token expires, and provisioning stops dead when it does. Expiry is mandatory and capped at two years — there is no permanent token. Vaks PM emails a reminder 14 days ahead, but put the date in your own calendar as well. When you rotate, note that Rotate revokes the old token immediately, so update your directory in the same maintenance window.

If you run several organizations on separate subdomains, each one needs its own tenant URL, its own token and its own provisioning application — the tenant is identified by the hostname you call.

If your instance is not reachable from the internet. Provisioning is the directory calling you, not the reverse — so a self-hosted instance published only on your internal network cannot be reached by a cloud directory. Both Entra and Okta solve this with a lightweight agent installed inside your network, which keeps only outbound connections to the directory: no inbound firewall port, no public exposure of the tenant URL.
  • Entra — the provisioning agent, part of on-premises application provisioning. Requires an Entra ID P1 or P2 licence, like cloud provisioning.
  • OktaOn-Premises Provisioning (OPP), with the Okta Provisioning Agent on a Windows or Linux host.
Everything else in this guide is unchanged: the same tenant URL (an internal address in this case), the same token, the same attribute mappings. Only the network path differs. Install and register the agent following your vendor's documentation, then come back to step 2.

Step 2 — In Microsoft Entra ID

  1. Go to Microsoft Entra admin center → Identity → Applications → Enterprise applications and open the application you created for single sign-on (or create a non-gallery application if provisioning is all you need).
  2. Open Provisioning → New configuration, or set Provisioning Mode to Automatic.
  3. Paste the Tenant URL and the Secret Token from step 1.
  4. Press Test Connection. It must succeed before you can save — this validates the token and the scope in one go.
  5. Under Users and groups, assign the people and groups to provision. Under Settings, set the provisioning scope, then set Provisioning Status to On.

Entra runs an initial full cycle, then incremental cycles roughly every 40 minutes. The first cycle can take a while on a large directory.

Step 2b — In Okta

  1. Open your Vaks PM application in the Okta admin console, go to the Provisioning tab and choose Configure API Integration.
  2. Tick Enable API integration. Enter the Base URL (the tenant URL from step 1) and the API Token (the secret token).
  3. Press Test API Credentials, then save.
  4. Under To App, enable Create Users, Update User Attributes and Deactivate Users.
  5. Assign users and groups, and push groups explicitly if you want teams created — Okta only sends groups you have added under Push Groups.

Step 3 — Attribute mappings

Only five attributes are stored. Everything else your directory sends is accepted and discarded, so trimming the mapping list is tidiness rather than necessity.

SCIM attributeBecomesNotes
userNameThe account's email addressRequired. Stored lower-cased. Map it to the user principal name or mail as you prefer, but keep it consistent with what single sign-on will present.
externalIdThe account keyMap this to the object ID, not to Entra's default. See the warning below.
activeAccount statusfalse suspends the account and releases its seat.
name.formatted or displayNameDisplay nameFalls back to given name + surname, then the email. First and last names are not stored separately.
employeeNumber optionalEmployee identifierFrom the enterprise extension. Not sent by default — add the mapping explicitly if you want it. Must be unique across the organization.
Change the default externalId mapping. Entra maps it to mailNickname out of the box, which changes when a user is renamed — and when it changes, the directory stops recognising the account it created, then tries to create a duplicate and gets a conflict. Map externalId to objectId instead. This is also the value single sign-on matches on, so the two integrations converge on the same account.

Matching attributes — what can be filtered on

Before creating anyone, your directory asks whether the account already exists, by querying this endpoint with a filter. Entra lets you choose which attribute it matches on (Match objects using this attribute); Okta always matches on userName and offers no choice. If Entra is pointed at an attribute that cannot be filtered, every lookup fails.

ResourceFilters accepted
UsersuserName eq "…" · externalId eq "…" · emails[type eq "work"].value eq "…" · id eq "…"
GroupsdisplayName eq "…" · externalId eq "…" · id eq "…"

Only equality on a single attribute is supported. Compound filters (and, or), the other comparison operators (ne, co, sw, gt…) and presence tests (pr) are refused with a 400. Attribute names may carry their schema prefix (urn:ietf:params:scim:schemas:core:2.0:User:userName) and are matched case-insensitively.

Set exactly one matching attribute in Entra. Leaving several enabled makes Entra query on each in turn, and the first one this endpoint cannot filter fails the cycle. Keep userName (or externalId) and clear the rest.

Step 4 — Groups and teams

A directory group becomes a Vaks PM team: the group's display name becomes the team name, and its members become team members. Teams created this way are matched on the group's external identifier, so renaming the group in the directory renames the team rather than creating a second one.

Two behaviours regularly cause a support ticket that turns out to be normal:

Removing a group from the directory soft-deletes the team; its members keep their accounts. If the team had automatic licensing on, its members lose their seats unless another automatic-licensing team covers them.

Step 5 — Verify

After the first cycle completes, check three things:

  1. In your directory's provisioning log — users created, no recurring errors. Entra's log names each user and the outcome.
  2. In Admin → Users — the expected people are present. Remember they will have no seat yet unless an automatic-licensing team covers them.
  3. End to end — have one pilot user sign in through single sign-on. That proves the object identifier lines up between provisioning and federation, which is the single thing most likely to be wrong.

Then test a leaver: deactivate the pilot user in the directory, wait for a cycle, and confirm their Vaks PM account shows as suspended and their sessions are gone.

Deactivation and deletion

Action in the directoryEffect in Vaks PM
User deactivated (active: false) or unassigned from the applicationAccount suspended, licence seat released, and all active sessions revoked immediately. Data and history preserved.
User reactivatedAccount active again, but the seat is not restored automatically — grant it again, or rely on an automatic-licensing team.
User deletedSoft delete: the account is suspended and hidden, its data retained.
A previously deleted person is provisioned againThe original account is restored in place, with its history, time entries and comments intact. Convenient for a returning employee; worth knowing before you re-provision someone by accident.

To erase someone's personal data rather than suspend them, use the anonymization function in the admin panel — provisioning has no equivalent, by design.

Troubleshooting

Error details returned to your directory are always in English, whatever your interface language — the caller is a machine and the text lands in its provisioning log. They appear verbatim there.

SymptomCause & fix
Test connection fails · Missing SCIM tokenNo usable authorization header arrived. Re-paste the token; check for a stray space or line break.
Test connection fails · Invalid or revoked SCIM tokenThe token is unknown, revoked or expired. Generate a new one. Also check you are calling the right hostname — a token from one organization does not work on another's subdomain.
Token lacks the scim:provision scopeAn ordinary API key was used. Use the Generate SCIM token button, which sets the scope for you.
403 · This feature ("scim") requires an active licenseThe licence does not cover SCIM. Import one under Admin → Organization → License.
400 · Filtering on '…' is not supportedThe directory looked accounts up by an attribute this endpoint cannot filter on. In Entra, set Match objects using this attribute on userName or externalId only, and clear it everywhere else. See matching attributes for the accepted list.
400 · The operator '…' is not supportedThe filter used something other than a single eq comparison. Same fix: simplify the matching configuration. Sustained failures put an Entra provisioning job in quarantine; it resumes on its own once the configuration stops failing.
409 · User already existsAn account already holds that email or external identifier. Usually the externalId mapping was changed after the first cycle, so the directory no longer recognises accounts it created. Restore the mapping to objectId.
409 · userName (email) already used by another accountA rename would collide with a different account. Resolve the duplicate in the directory.
409 on a team nameA team of that name already exists but was not created by provisioning. Rename one of the two.
Provisioning worked, then stopped entirelyThe token expired. There is no grace period.
Users provisioned but cannot see anythingNo licence seat. Expected — see provisioning and seats.
Groups arrive with no membersNormal on the first cycle. If it persists, the members are not in the provisioning scope.
The directory keeps creating duplicatesIt is not finding existing accounts. Confirm externalId is mapped to objectId and that provisioning has not been reconfigured from scratch, which resets the directory's internal links.

What is logged

Every provisioning write is audited, attributed to the administrator who generated the token, and visible under Admin → Security & Compliance → Audit log: account creation (flagged when it restored a previously deleted account), suspension, reactivation, deletion, and team membership changes. Membership entries record which members were requested, which were added, and which were dropped for not existing yet — the reliable place to confirm the empty-group behaviour above is benign.


Related: OIDC single sign-on · SAML single sign-on · all integrations.