Describe the bug
The Dashboard's profile page (/profile) saves changes using the updateAdministrator mutation, which is gated by Permission.UpdateAdministrator. As a result, any administrator whose role does not include UpdateAdministrator cannot edit their own first name, last name, email address, or password — the page loads and the form is editable, but saving fails with a permission error.
The Admin API already has a mutation intended for exactly this case: updateActiveAdministrator, which is gated by Permission.Owner and resolves the target id from ctx.activeUserId, so it can only ever modify the calling user's own administrator. The Dashboard does not use it anywhere.
Note the asymmetry within the same page: the activeAdministrator query that loads the page is correctly gated by Permission.Owner, so the page renders fine for every logged-in admin. Only the save path requires the elevated permission.
Relevant source (v3.6.5):
packages/dashboard/src/app/routes/_authenticated/_profile/profile.graphql.ts — declares updateAdministratorDocument using updateAdministrator.
packages/dashboard/src/app/routes/_authenticated/_profile/profile.tsx:51 — passes it as updateDocument to useDetailPage.
packages/core/src/api/resolvers/admin/administrator.resolver.ts — updateActiveAdministrator is @Allow(Permission.Owner); updateAdministrator is @Allow(Permission.UpdateAdministrator).
To Reproduce
Steps to reproduce the behavior:
- Create a Role that does not include
UpdateAdministrator — for example a shop-staff role with catalog/order permissions only, plus Permission.Authenticated.
- Create an Administrator and assign that role.
- Log in to the Dashboard as that administrator.
- Go to
/profile (user menu → Profile). The page loads correctly and shows the current first name, last name, email address and authentication methods.
- Change the first name (or type a new password) and click Update.
- A toast appears:
Failed to update profile with the description You are not currently authorized to perform this action. Nothing is saved.
Expected behavior
Every logged-in administrator can edit their own profile, regardless of whether their role grants UpdateAdministrator. Editing one's own name, email address and password is self-service and should only require being authenticated — which is what Permission.Owner and the existing updateActiveAdministrator mutation express.
Actual behavior
The save is rejected with a FORBIDDEN error unless the administrator's role includes UpdateAdministrator. Because UpdateAdministrator is the permission that governs editing other administrators, the only way to let a user edit their own profile today is to also let them edit other administrators.
Error logs
GraphQL response from the UpdateAdministrator mutation:
{
"errors": [
{
"message": "You are not currently authorized to perform this action",
"extensions": { "code": "FORBIDDEN" },
"path": ["updateAdministrator"]
}
],
"data": null
}
Server log:
warn <timestamp> [GraphQL] You are not currently authorized to perform this action
Environment (please complete the following information):
- @vendure/core version: 3.6.5 (
@vendure/dashboard 3.6.5)
- Nodejs version: 24.18.0
- Database (mysql/postgres etc): PostgreSQL
- Operating System (Windows/macOS/Linux): Windows 11 (also applies on Linux — this is not platform-specific)
- Browser (if applicable): Chrome
- Package manager (npm/yarn/pnpm): npm 12.0.1
Configuration
No special configuration is required to reproduce — this reproduces on a default config. The only requirement is a Role that omits UpdateAdministrator, e.g.:
await roleService.create(ctx, {
code: 'shop-staff',
description: 'Shop staff',
channelIds: [channel.id],
permissions: [
Permission.Authenticated,
Permission.ReadCatalog,
Permission.UpdateCatalog,
Permission.ReadOrder,
Permission.UpdateOrder,
// no Permission.UpdateAdministrator
],
});
Minimal reproduction
No repository needed — the two steps above (create a role without UpdateAdministrator, log in as a member of it, try to save /profile) reproduce it on a stock Vendure install.
Suggested fix
Point the profile page at the mutation that already exists for this purpose. In profile.graphql.ts:
-export const updateAdministratorDocument = graphql(`
- mutation UpdateAdministrator($input: UpdateAdministratorInput!) {
- updateAdministrator(input: $input) {
+export const updateActiveAdministratorDocument = graphql(`
+ mutation UpdateActiveAdministrator($input: UpdateActiveAdministratorInput!) {
+ updateActiveAdministrator(input: $input) {
id
}
}
`);
and update the import and updateDocument reference in profile.tsx accordingly.
One non-obvious detail: setValuesForUpdate in profile.tsx currently returns id: entity.id, and useDetailPage submits the form values verbatim as the mutation input. Since UpdateActiveAdministratorInput has no id field, that line has to be dropped as part of the change or every save fails schema validation:
setValuesForUpdate: entity => {
return {
- id: entity.id,
firstName: entity.firstName,
UpdateActiveAdministratorInput exposes exactly the five fields the profile form edits (firstName, lastName, emailAddress, password, customFields) and deliberately omits roleIds, so this also removes the theoretical possibility of the profile form touching role assignments.
Workaround
We patch the two Dashboard source files in node_modules/@vendure/dashboard from a postinstall script, applying the diff shown above (swap the mutation document, update the import and updateDocument, and drop id from setValuesForUpdate). With that patch applied, npm run build:dashboard succeeds and administrators on restricted roles can edit their own profiles without being granted UpdateAdministrator.
Additional context
- Happens consistently, on every save attempt, for every role lacking
UpdateAdministrator.
- Not triggered by any recent change on our side — it is the behaviour of a stock 3.6.5 Dashboard.
- Context for why this matters to us: we run a multi-tenant setup where each merchant store is a Channel, and merchant-facing roles are deliberately scoped. Granting those roles
UpdateAdministrator purely to unblock self-service profile editing would give them a considerably broader capability than intended, so the profile page is effectively unusable for every non-superadmin user.
Describe the bug
The Dashboard's profile page (
/profile) saves changes using theupdateAdministratormutation, which is gated byPermission.UpdateAdministrator. As a result, any administrator whose role does not includeUpdateAdministratorcannot edit their own first name, last name, email address, or password — the page loads and the form is editable, but saving fails with a permission error.The Admin API already has a mutation intended for exactly this case:
updateActiveAdministrator, which is gated byPermission.Ownerand resolves the target id fromctx.activeUserId, so it can only ever modify the calling user's own administrator. The Dashboard does not use it anywhere.Note the asymmetry within the same page: the
activeAdministratorquery that loads the page is correctly gated byPermission.Owner, so the page renders fine for every logged-in admin. Only the save path requires the elevated permission.Relevant source (v3.6.5):
packages/dashboard/src/app/routes/_authenticated/_profile/profile.graphql.ts— declaresupdateAdministratorDocumentusingupdateAdministrator.packages/dashboard/src/app/routes/_authenticated/_profile/profile.tsx:51— passes it asupdateDocumenttouseDetailPage.packages/core/src/api/resolvers/admin/administrator.resolver.ts—updateActiveAdministratoris@Allow(Permission.Owner);updateAdministratoris@Allow(Permission.UpdateAdministrator).To Reproduce
Steps to reproduce the behavior:
UpdateAdministrator— for example a shop-staff role with catalog/order permissions only, plusPermission.Authenticated./profile(user menu → Profile). The page loads correctly and shows the current first name, last name, email address and authentication methods.Failed to update profilewith the descriptionYou are not currently authorized to perform this action. Nothing is saved.Expected behavior
Every logged-in administrator can edit their own profile, regardless of whether their role grants
UpdateAdministrator. Editing one's own name, email address and password is self-service and should only require being authenticated — which is whatPermission.Ownerand the existingupdateActiveAdministratormutation express.Actual behavior
The save is rejected with a
FORBIDDENerror unless the administrator's role includesUpdateAdministrator. BecauseUpdateAdministratoris the permission that governs editing other administrators, the only way to let a user edit their own profile today is to also let them edit other administrators.Error logs
GraphQL response from the
UpdateAdministratormutation:{ "errors": [ { "message": "You are not currently authorized to perform this action", "extensions": { "code": "FORBIDDEN" }, "path": ["updateAdministrator"] } ], "data": null }Server log:
Environment (please complete the following information):
@vendure/dashboard3.6.5)Configuration
No special configuration is required to reproduce — this reproduces on a default config. The only requirement is a Role that omits
UpdateAdministrator, e.g.:Minimal reproduction
No repository needed — the two steps above (create a role without
UpdateAdministrator, log in as a member of it, try to save/profile) reproduce it on a stock Vendure install.Suggested fix
Point the profile page at the mutation that already exists for this purpose. In
profile.graphql.ts:and update the import and
updateDocumentreference inprofile.tsxaccordingly.One non-obvious detail:
setValuesForUpdateinprofile.tsxcurrently returnsid: entity.id, anduseDetailPagesubmits the form values verbatim as the mutationinput. SinceUpdateActiveAdministratorInputhas noidfield, that line has to be dropped as part of the change or every save fails schema validation:setValuesForUpdate: entity => { return { - id: entity.id, firstName: entity.firstName,UpdateActiveAdministratorInputexposes exactly the five fields the profile form edits (firstName,lastName,emailAddress,password,customFields) and deliberately omitsroleIds, so this also removes the theoretical possibility of the profile form touching role assignments.Workaround
We patch the two Dashboard source files in
node_modules/@vendure/dashboardfrom apostinstallscript, applying the diff shown above (swap the mutation document, update the import andupdateDocument, and dropidfromsetValuesForUpdate). With that patch applied,npm run build:dashboardsucceeds and administrators on restricted roles can edit their own profiles without being grantedUpdateAdministrator.Additional context
UpdateAdministrator.UpdateAdministratorpurely to unblock self-service profile editing would give them a considerably broader capability than intended, so the profile page is effectively unusable for every non-superadmin user.