View-only unless a role grants editing
A role grants editing only through a flag that says so:addChart, addFilter, createChart, editCharts, removeChart, addDashboard or canDuplicateDashboard set to true. readOnly overrides all of them.
Every other user is view-only:
- a role stored with no permissions (
{}), or with none of those flags; - a role with
readOnly: true; - a project user with no role at all.
This matches v1: a tenant registered without
tenantEditingPermissions was view-only.The permissions
“Unset” is what a flag means when the role does not mention it. A flag marked on if the role edits is on only when the role grants editing through another flag, and off on a view-only role.
Spell out every flag you care about rather than relying on “Unset”. A role that says what it grants reads the same everywhere and survives a change of defaults.
Two common roles
A reader — sees and filters, changes nothing:Managing roles
In the Hub: Project settings → Roles. With the API, using the same API key asembed-token:
Role names are unique within a project; creating a second role with a taken name answers
409.
Giving a user a role
- At sign-in.
embed-tokentakesuser.userRoleId, applied on every call that sends it, anduser.defaultUserRoleId, applied only to a user it creates. SenduserRoleIdwhen your product decides the role; senddefaultUserRoleIdwhen the role is managed in Upsolve after the first sign-in. - Later.
PUT /v1/api/projects/{projectId}/users/{projectUserId}withuserRoleId.nullremoves the role.
When a change takes effect
A user’s token carries their role’s permissions as they were when it was issued. After you change a role, or move a user to another one, the user’s next token has the new permissions; a token already issued keeps the old ones until it expires (1h by default). The API’s checks on dashboard writes read the role when the write arrives, so they apply at once.
Coming from the v1 SDK’s tenantEditingPermissions prop
In v1 an integration could give its users permissions in two places: in the register-tenant call, and in the tenantEditingPermissions prop of the SDK component. The SDK laid the prop over the token’s permissions in the browser. The prop was never stored, so a migration to v2 cannot see it: the roles it proposes come from what register-tenant was sent alone. In v2 an embed takes its permissions from the user’s role and nothing else, so the prop’s permissions have to go on the role.
v1 and v2 read a flag nobody set differently. v1 turned it off. A v2 role that grants editing takes the “Unset” defaults above for the editing flags it leaves out. So a v1 prop of { "addFilter": true } copied onto a role as it is would also grant Add chart, Create chart, Remove chart and new dashboards. Write every editing flag out:
aiInsight, drillDown, hideHeader, …) as the prop has it.
Already migrated
Update the role the migration created with the prop’s permissions, written out as above. Tenants registered without permissions all share one migrated role, so this is usually one call. Every user on the role gets the permissions on their next token.Migrating now
Run the migration’s two role steps through the API with the prop, then continue in the Hub. The Hub’s migration page proposes roles without the prop.-
Propose the roles.
POST /v1/api/migration/analyze-roleswith your prop assdkTenantEditingPermissions. Each proposed role is what v1 showed its users: their v1 token with the prop laid over it, every editing flag written out. -
Create them.
POST /v1/api/migration/create-roleswith each proposed role’spermissionsandtenantIds, and anameof your choice. - Continue on the Hub’s migration page from Create Project Users. The role steps are marked done, so the page does not run them again.
register-tenant, which never sees the prop: send register-tenant the prop’s permissions from then on, and it finds the same role.