User context — /me payload structure
Complete structure of the /me payload: identity, access levels, teams, application rights and features.
User context — /me payload structure
/meis your frontend source of truth for everything related to the identity and rights of the current user. Call it once after login, and store the result in a React context.
Why this step matters
The Keycloak JWT contains minimal identity (sub, email, admin levels). But to build a conditional UI (hide/show buttons based on rights, display the correct organization name, etc.), you need the complete payload that only the /me API returns.
/me aggregates data from multiple sources (Keycloak claims, config DB, profiles, teams) into a single call.
Key concepts
- adminLevel: the user's hierarchical admin level (WakaAdmin → None).
- appRights: list of
resource.action-type application rights accumulated from profiles. Details of the actual shape (profile.rights,{code, name, description, category}objects) in the access control model. - features: activation checked in cascade across App ∧ Network ∧ Customer via a dedicated endpoint (see access control model) — not a precomputed field of
/me. - profiles: WakaStart profiles assigned to the user (determines appRights).
- teams: teams the user is a member of, with their level and rights within each team.
Call
httpGET /api/me Authorization: Bearer <keycloak_access_token> x-enriched-token: <wakastart_token>
Both headers are required. The response is the same whether the caller uses a Bearer JWT or an API key.
Full response
json{ "id": "550e8400-e29b-41d4-a716-446655440000", "wid": "WKST05", "email": "john@acme.com", "firstName": "John", "lastName": "Doe", "keycloakId": "kc-550e8400-e29b-41d4-a716-446655440000", "isActive": true, "adminLevel": "CustomerAdmin", "hdsRoles": [], "customer": { "id": "uuid", "wid": "ACM001", "name": "Acme Corp", "subdomain": "acme" }, "partner": { "id": "uuid", "wid": "PTR001", "name": "Wakastellar" }, "network": { "id": "uuid", "wid": "NET001", "name": "Production" }, "teams": [ { "id": "uuid", "wid": "TEAM01", "name": "DevOps", "teamLevel": "ADMIN", "appRights": "rw" } ], "profiles": [ { "id": "uuid", "wid": "PRF001", "name": "Administrateur" } ], "appRights": [ "partners.read", "users.read", "users.write", "users.create", "users.update", "users.delete", "apps.read", "apps.create", "teams.read", "teams.members.add", "infra.read", "infra.deploy", "audit.read", "profiles.assign", "api-keys.read", "api-keys.create", "api-keys.revoke" ], "lastLoginAt": "2026-05-19T10:30:00.000Z", "createdAt": "2026-01-15T08:00:00.000Z" }
Description of each field
Identity
| Field | Type | Description |
|---|---|---|
id | UUID | Internal database identifier |
wid | string | Short identifier (6 chars) for URLs |
email | string | User's email (lowercase) |
firstName / lastName | string | First name / last name |
keycloakId | string | Keycloak UUID (JWT sub) |
isActive | boolean | Active account. If false, enrichment fails |
Access levels
| Field | Type | Description |
|---|---|---|
adminLevel | string | Hierarchical admin level (see table below) |
The
userLevelfield is no longer returned by/me— it has been removed from the payload (MeResponseDtono longer carries it). It is no longer used to gate invitation creation (see Invitations API — Creation); access control relies exclusively onadminLevelandappRights(profiles).
adminLevel hierarchy:
textWakaAdmin → Full platform access (Wakastellar super-admin) OwnerAdmin → Full platform access (partner owner) AppsAdmin → Applications, profiles, rights NetworkAdmin → Networks, customers, apps CustomerAdmin → Customers, users, teams User → Basic access (own profile) None → No admin access
Hierarchical: a NetworkAdmin also holds the rights of CustomerAdmin and User.
Multi-tenant context
| Field | Type | Description |
|---|---|---|
customer | object | Customer the user belongs to |
partner | object | Parent partner of the customer |
network | object | Parent network of the customer |
HDS roles
| Field | Type | Description |
|---|---|---|
hdsRoles | string[] | HDS (Healthcare Data Security) roles: HDS_ADMIN, HDS_PATIENT, etc. |
The
wakaRolesfield (cross-cutting business roles CONFIG/EXPLOIT/DPO/AUDIT/BILLING/CYBER) has been decommissioned on the platform side — do not rely on it, even if it still appears in older code or documentation.
Teams
appRights within the team context is a free-form field encoded on the team (distinct from the user's global appRights).
Profiles and application rights
profiles: assigned profiles. A profile = a set ofAppRights in the DB.appRights: deduplicated and merged array of all rights coming from all profiles. Format:{resource}.{action}.features: this is NOT a precomputed field of/me— check cascade activation (App ∧ Network ∧ Customer) viaGET /api/config/app-features/check/{customerWid}/{featureCode}. Example feature codes:invitations,antivirus,hds.
What's in /me vs in the JWT
[!WARNING] The enriched JWT (wakaToken) is signed and must fit under the 4 KB cookie limit. Several claims that used to be present have been removed from it and are now available only via
/me:hdsRoles, team rights (wgrl), and profiles. ThewakaRolesconcept itself has been decommissioned (neither in the JWT nor in/me). If your code still reads this information directly from the decoded JWT instead of via/me, it is reading stale or missing values.
| Data | Enriched JWT (wakaToken) | /me (API) |
|---|---|---|
Identity (sub, email, keycloakId, given_name, family_name) | yes | yes |
adminLevel (wadl) | yes | yes |
userLevel (wusl) | no (ws-serv-token no longer emits this claim in the wakaToken) | no (removed from the /me payload) |
Partner/Network/Customer/App WIDs (pid/nid/cid/aid) | yes | yes (full objects) |
User WID (uid) | no (absent from the signed JWT) | yes |
Theme, language, Keycloak org, environment (wthm/wlng/woid/wenv) | yes | — |
hdsRoles | no | yes |
Team rights (wgrl) | no | yes (decoded, arrays) |
| Profiles | no | yes |
appRights (full list) | no | yes |
lastLoginAt | no | yes |
The JWT contains identity, access levels and multi-tenant context — enough to route and perform a first coarse check. Everything related to team rights and profiles lives exclusively in /me; feature activation is checked via a dedicated endpoint (see above): call /me systematically before building a conditional UI or a guard based on these fields.
Go further
- /me cache and invalidation: when to call
/me, caching, invalidation - Access control: how to use
appRightsin your guards - Using the API: how to pass tokens in your requests