Users and profiles
The directory profile model, who can edit which fields, the matching OIDC claims, the account lifecycle and GDPR self-service.
Every user in your organization carries a small, deliberate directory profile. This page describes the fields, who writes them, how they surface in tokens, and the lifecycle operations an administrator (or SCIM) performs on the account.
The profile model
| Field | API key | OIDC claim | SCIM attribute |
|---|---|---|---|
| First name | givenName | given_name | name.givenName |
| Last name | familyName | family_name | name.familyName |
| Display name | displayName | name | displayName |
| Job title | jobTitle | (none) | title |
| Department | department | (none) | enterprise extension department |
| Language | locale | locale | locale |
All fields are optional. The effective display name is computed from a single rule everywhere (API, OIDC, SCIM): the explicit display name if set, otherwise "First name Last name" if at least one is present, otherwise the email address. locale is an RFC 5646 tag (fr, en, en-US).
There is deliberately no date of birth field. Obexal applies GDPR data minimization: an IdP does not need it to authenticate anyone.
Who edits what
The directory belongs to the organization. Profile fields are written by an admin or by inbound SCIM; the employee sees them read-only through GET /v1/auth/me. There is no self-service write endpoint (no PATCH /v1/me/profile). The one exception: at invitation activation, the invitee may set or complete their own first and last name.
An admin edits the profile with PUT /v1/admin/users/{userId} (permission to manage members). The request replaces every field: an omitted or empty field is cleared.
curl -sS -X PUT https://accounts.obexal.com/v1/admin/users/<userId> \
-H "Authorization: Bearer $OBEXAL_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"givenName":"Alice","familyName":"Martin","displayName":"","jobTitle":"CFO","department":"Finance","locale":"fr"}'
# 200 -> {"status":"ok"} (audit event: user.profile_updated)The email address is the enterprise identity of the account: employees cannot change it themselves (the self-service endpoint answers 403 email_change_forbidden by default). Email changes go through an admin process or SCIM. The full directory listing is available at GET /v1/admin/users.
Profile claims in tokens
With the profile scope, the ID token and /oauth/userinfo carry given_name, family_name, name (the computed display name, omitted if it would just repeat the email) and locale, each emitted only when set. With the email scope: email and email_verified.
Job title and department are not standard OIDC claims, so they are not emitted in tokens; they are exposed through SCIM (title and the enterprise extension). Group membership surfaces as a groups claim: see Groups and app access.
Account lifecycle
Lifecycle operations are admin actions, each recorded in the audit log:
| Operation | Endpoint | Effect |
|---|---|---|
| Suspend | POST /v1/admin/users/{userId}/suspend | Status becomes deactivated, all sessions revoked, sign-in refused |
| Reactivate | POST /v1/admin/users/{userId}/reactivate | Status back to active |
| Force logout | POST /v1/admin/users/{userId}/logout | All sessions revoked, account stays active |
| Unlock | POST /v1/admin/users/unlock | Clears the anti-bruteforce lock for {"email":"..."} |
Suspension takes an optional JSON body {"reason":"offboarding"}, kept in the audit trail. Two guards apply: only an owner can suspend an owner, and the last owner of an organization can never be suspended.
curl -sS -X POST https://accounts.obexal.com/v1/admin/users/<userId>/suspend \
-H "Authorization: Bearer $OBEXAL_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"reason":"offboarding"}'
# 200 -> {"status":"ok"} (audit event: admin.user.suspended)If outbound SCIM provisioning is configured, suspension automatically deactivates the account on every downstream target, and reactivation pushes it back.
Removing a member with DELETE /v1/admin/members/{userId} only removes their role in the organization; it does not suspend or delete the account.
GDPR export and deletion
A signed-in user can export their data at any time (right to portability): GET /v1/auth/account/export returns a JSON attachment with the public profile, linked federated identities and MFA factor metadata. It never contains secrets (no password hash, no TOTP seed). The export is audited (auth.account.exported).
Self-service account deletion exists (POST /v1/auth/account/delete, with re-authentication by password, or by exact email confirmation for passwordless accounts) but is disabled by default: in a managed directory, the account lifecycle belongs to the organization, and the endpoint answers 403 account_delete_forbidden. Self-hosted deployments serving consumer tenants can enable it: see Configuration. When it runs, deletion revokes all sessions and removes the account permanently; the audit entry keeps only the user id, never the email. See GDPR for the full picture.