Sets the custom Okta profile attribute entityStatus on every active user —
forProfit or nonProfit — derived from the domain of their Okta login.
Status: complete, run live 2026-05-20. Safe to re-run whenever the entity list changes or a new domain appears; it is idempotent and only writes the genuine delta.
The Schmidt family of entities mixes for-profit and non-profit organizations, and several downstream decisions depend on knowing which is which — app assignment rules, reporting splits, and access policies that should not span the boundary. Okta knew a user’s entity but not its tax status, so that had to be answered by hand every time.
Source of truth is the “Schmidt Entity List + Tax Status” Google Sheet. Rather
than wire up a live sheet read for a value that changes once or twice a year, the
mapping is a lookup table in the script — 37 domains. When the sheet changes,
update DOMAIN_TO_STATUS and re-run.
ACTIVE Okta user with full Link-header pagination.DOMAIN_TO_STATUS.entityStatus already on the profile.Unmapped domains are left blank and reported — never guessed at. That bucket deliberately covers the Spinning Out / Ignore entities (hLevel, Swift Beat) plus contractors, service accounts, and any domain not yet added to the table.
forProfit and nonProfit are the enum values on the Okta schema, not the
display names. Okta renders “For-Profit” / “Non-Profit” in the admin UI from the
schema definition, so the admin console will not match what the script prints.
cd integrations/okta_entity_status
npm install
cp .env.example .env # then fill in OKTA_DOMAIN and OKTA_API_TOKEN
The token needs profile-edit rights (Super Admin or User Admin). Revoke it when the run is finished — house rule.
Okta scopes custom profile attributes to each User Type’s schema, not to the
org. If entityStatus is missing from a given User Type, every write against a
user of that type fails with:
Property name 'entityStatus' is not defined in profile
The dry run groups failures by User Type precisely so you can see which schemas need the attribute added first (Directory → Profile Editor → that User Type). Do that before going live, or a whole class of users silently no-ops.
npm run dry-run # pulls users, joins to the lookup table, prints payloads — no writes
npm run run-live # writes the updates
DOMAIN_TO_STATUS lives near the top of sync-entity-status.js and is keyed by
login domain. To add an entity, add its domain(s) with the matching enum value and
re-run — no other change needed.
Intentionally absent, and reported as unmapped rather than mapped:
This mirrors EXCLUDE_ENTITIES in okta_profile_sync
and SPINOUT_ENTITIES in okta_license_cleanup. If
an entity’s status changes in one of those, check the other two.
Every run writes a JSON audit log and a Confluence-ready markdown report next to the script, covering: the write summary, per-User-Type failures, the unmapped bucket with counts by domain, and the full per-user detail. Both contain employee data and are gitignored.