How to migrate from raw_attributes and legacy standard attributes to custom attributes.
On April 15, 2026, two changes take effect across Directory Sync and SSO:
raw_attributes will stop returning data. The field will return an empty object everywhere your integration consumes it:
dsync.user.created, dsync.user.updated, dsync.user.deleted) and group events (dsync.group.created, dsync.group.deleted, dsync.group.user_added, dsync.group.user_removed)Top-level job_title, username, and emails will be removed from Directory User objects. These fields will return null (or [] for emails).
Your customers do not need to make any changes. You do not need to coordinate with your customers’ IT admins or ask them to remap anything. See the migration paths below for what you need to do.
If your code reads from raw_attributes on Directory Users or SSO Profiles, contact us and we will automatically set up the equivalent custom attribute mappings across all of your existing connections. You then update your code to read from custom_attributes instead.
You can also configure custom attribute mappings yourself from the IdP Attributes page in the Dashboard. See Custom Attributes for Directory Sync or Custom Attributes for SSO for details.
// Directory Sync - nested fields const licenseTier = user.raw_attributes[ 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' ]?.license_tier; const employeeId = user.raw_attributes.customSchemas?.Company?.employeeId; // SSO const department = profile.raw_attributes.department;
// Directory Sync - custom attributes const licenseTier = user.custom_attributes.license_tier; const employeeId = user.custom_attributes.employee_id; // SSO const department = profile.custom_attributes.department_name;
Using AuthKit? If you access raw_attributes via the SSO Profile or Directory User API, the migration above applies to you. Additionally, you can now access IdP attributes directly in AuthKit JWTs and the Organization Membership API – no standalone API call needed. See Custom Attributes in AuthKit.
If your code reads job_title, username, or emails from the top level of Directory User objects, you can migrate without contacting us:
custom_attributes with a fallback to the top-level field, then deploy.This order ensures no data is missed during the transition – your code handles both locations until the predefined attribute is active.
const jobTitle = user.job_title; const emails = user.emails; const username = user.username;
const jobTitle = user.custom_attributes?.job_title ?? user.job_title; const emails = user.custom_attributes?.emails ?? user.emails; const username = user.custom_attributes?.username ?? user.username;
const jobTitle = user.custom_attributes.job_title; const emails = user.custom_attributes.emails; const username = user.custom_attributes.username;
If you use emails only to get the user’s primary email address, you can use the email standard attribute instead, which remains on the top-level Directory User object.
{ "id": "directory_user_xxxxx", "idp_id": "xyz", "email": "marcelina@example.com", "job_title": "Software Engineer", "username": "marcelinadavis", "emails": [ { "type": "work", "value": "marcelina@example.com", "primary": true } ], "custom_attributes": {}, "raw_attributes": { "name": { "givenName": "Marcelina", "familyName": "Davis" }, "userName": "marcelinadavis", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { "department": "Engineering", "costCenter": "R&D" } } }
{ "id": "directory_user_xxxxx", "idp_id": "xyz", "email": "marcelina@example.com", "custom_attributes": { "job_title": "Software Engineer", "username": "marcelinadavis", "emails": [ { "type": "work", "value": "marcelina@example.com", "primary": true } ], "department_name": "Engineering", "cost_center_name": "R&D" } }