SCIM provisioning: Entra ID and Okta
Your directory becomes the front door of the card holder roster: a new employee appears in the portal ready to photograph, a change of name or department flows through on the next provisioning cycle, and a leaver’s holder record deactivates itself. No CSV, no re-keying.
Two things from Settings → Integrations → SCIM provisioning:
- Tenant URL:
https://app.cardoffice.nz/api/scim/v2(your own host if self-hosted) - Secret token: created there, shown once
Provisioning targets the card holder roster, not staff portal accounts — those come from single sign-on and invitations.
What maps to what
Section titled “What maps to what”| Directory sends | Becomes | Notes |
|---|---|---|
name.givenName / name.familyName |
First / last name | Required |
userName |
(internal matching) | Entra sends the UPN |
externalId |
(internal matching) | The IdP’s stable anchor |
emails (primary, else work) |
||
phoneNumbers (primary, else work) |
Phone | |
employeeNumber (enterprise ext.) |
ID number — printed on cards | Map your employeeId here |
department (enterprise ext.) |
Department | |
userType |
Holder type | Via the token’s mapping table; unmatched values use the token’s default |
nickName |
Preferred name | displayName is used only when it differs from “first last” |
active |
Status | false → inactive; true reactivates |
Not written by SCIM, ever: photos, expiry dates, custom fields (the legacy bridge’s keys survive untouched), digital-ID preference, or any linked self-service account.
People who already exist
Section titled “People who already exist”The roster usually predates provisioning. The service adopts rather than duplicates: an incoming person is matched by the IdP anchor first, then by employee number against holders no connector has claimed. Entra’s initial reconciliation may also match by email where nothing else is stamped yet. After the first successful push, the IdP’s anchor owns the match and email changes follow the person.
If two people in the directory carry the same employee number, the second push is refused with a conflict (visible in the IdP’s provisioning log) — the same person-vs-ID discipline the legacy bridge enforces. Clean up the directory value; the portal will not guess which human is which.
What a leaver looks like
Section titled “What a leaver looks like”The IdP disables or deletes the user → the holder’s status becomes inactive. Nothing is deleted: photos, card history and audit trail stay, and the retention policy governs them as usual. One deliberate boundary: if the person also had a self-service portal login, deactivating the roster entry does not revoke that login — directories flap (leave, contract gaps, re-hires), and taking someone’s account away is an operator’s decision. Revoke it from the holder page when it should really go.
Entra ID
Section titled “Entra ID”Proven end to end against production on 26 Aug 2026 (tenant cardoffice.onmicrosoft.com → the CardOffice organisation). Followed in this order, it works first time.
Before the app — three fields on every user you will provision. The provisioning mappings read attributes Entra’s new-user wizard does not require, and each gap has a consequence:
| Entra user field (Properties) | Feeds | Without it |
|---|---|---|
| First name + Last name (Identity) | the holder’s name | the create is refused — Display name alone is not enough |
| Employee ID (Job information) | the ID number printed on cards | holder arrives with no card number |
Email (Contact information — this is the mail attribute) |
the holder’s email (photo invites) | holder arrives without one; cloud-only accounts start with mail empty, so type a deliverable address in |
Put the people in one group (e.g. CardOffice Staff). Service and break-glass accounts stay out of it — group membership is the roster.
- Create the app: entra.microsoft.com → Enterprise applications → New application → Create your own → “Integrate any other application you don’t find in the gallery”.
- Provisioning → Automatic (Bearer authentication). Tenant URL is the
versioned path —
https://app.cardoffice.nz/api/scim/v2— plus the secret token from Settings → Integrations. Entra’s own error hint suggests a URL ending in/scim; that form 404s here. Test connection passes in seconds; Save. - Attribute mapping — the defaults are right; make exactly one edit:
map
employeeId→urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber. Leave every other row alone — the portal ignores what it doesn’t use, and a greyed-out target attribute in the picker means that mapping already exists (edit the row, never re-add). - Users and groups: assign the group.
- Prove one person: Provision on demand → pick someone → the result
table should end in a create with every expected attribute. Confirm the
holder in the portal (self-hosters:
ops/show-scim-holders.mjs --company <slug>shows the roster and the SCIM audit rows from the server side). - Turn provisioning On — the steady-state cycle runs roughly every 40 minutes from then on: joiners, renames, leavers, all automatic.
When something fails, it is one of three things:
| Symptom | Cause | Fix |
|---|---|---|
| HTTP 404 on test or provision | Tenant URL missing /api/scim/v2 |
Correct it in Connectivity, Save — and if a 404 persists after the fix, Restart provisioning (config Overview): the provisioning service caches connector config and a browser refresh does not clear it |
| 400 “name.givenName and name.familyName are required” | the user has no First/Last name — only a Display name | fill both in the user’s Properties, re-provision |
| Holder lands but no email (or no ID number) | the user’s mail (or Employee ID) attribute is empty — the mapping is fine |
fill the field, re-provision; check for typos, the value flows exactly as typed |
- Applications → Create App Integration → SCIM 2.0 Test App (OAuth Bearer Token), or add SCIM provisioning to an existing app integration.
- Provisioning → Integration: SCIM connector base URL = the tenant URL;
unique identifier field:
userName; authentication mode HTTP Header, Bearer = the secret token. - Enable Create Users, Update User Attributes, Deactivate Users.
- Under the app’s attribute mappings, map
employeeNumber(or your employee-ID field) to the enterpriseemployeeNumber, anduserTypeif you use the holder-type mapping. - Assign a test user, confirm the create in the portal, then assign groups.
Google Workspace
Section titled “Google Workspace”Google does not offer generic outbound SCIM to third-party apps, so a Workspace syncs the other way round — CardOffice reads the directory on a schedule with a delegated read-only credential. Same matching, adoption and audit behaviour as this page describes; different plumbing to get there. See Google Workspace directory sync.
Google sign-in itself is separate again, and covered by SSO: that decides who may open the portal, this decides who is on the roster.
Troubleshooting
Section titled “Troubleshooting”- Every SCIM write is in the audit log, labelled SCIM provisioning with the token’s ID — Settings-side answer to “why did this record change?”
- The IdP’s own provisioning log shows our exact error responses; conflicts
(
409 uniqueness) name the cause. 429responses mean the provisioning cycle is hammering — both IdPs back off automatically and retry.- Revoking the token stops provisioning instantly; nothing already created is touched.
© 2026 Secure ID Ltd. All rights reserved.Documentation licence and terms