Assign user access
This guide assigns roles to a site user. To give organization members access to a site, use organization members instead.
Console-only site access
Organization membership and site access for members are managed only in Console, on the organization's Members and Invitations screens. The role changes below apply to site users.
Assign and revoke roles
Before you begin
Confirm the username and role slug exist in the selected site. You must be signed in to change roles. Use Site roles to create or change a Site Role; this page only assigns or revokes existing roles.
Choose the assignment duration
- Permanent assignment: Omit
expires_at. The membership has no expiry. - Expiring assignment: Supply a future ISO 8601 timestamp in
expires_at. The same timestamp applies to every newly created username and role pair in that request.
The API rejects an expires_at value in the past. An active membership has no
expires_at value or one later than the current time. After it expires, the
membership record remains, but active role and app-access reads exclude it.
An existing username and role pair is silently skipped and counted as a success; the skip leaves its expiry unchanged. The JavaScript and Python user SDKs do not expose the dedicated expiry-update endpoint, so confirm the intended expiry before creating the assignment — assigning the same role again doesn't change it.
In TaruviBase Console, use the site's Users screen. In code, use the SDK calls below. These examples create one permanent assignment and one expiring assignment, then revoke the permanent assignment:
import {User} from '@taruvi/sdk';
const users = new User(taruvi);
const permanentAssignment = await users.assignRoles({
roles: ["support-viewer"],
usernames: ["onboarding-user"],
});
const expiringAssignment = await users.assignRoles({
roles: ["support-viewer"],
usernames: ["temporary-user"],
expires_at: "2027-01-31T23:59:59Z",
});
const revokeResult = await users.revokeRoles({
roles: ["support-viewer"],
usernames: ["onboarding-user"],
});
permanent_assignment = client.users.assign_roles(
roles=["support-viewer"], usernames=["onboarding-user"]
)
expiring_assignment = client.users.assign_roles(
roles=["support-viewer"],
usernames=["temporary-user"],
expires_at="2027-01-31T23:59:59Z",
)
client.users.revoke_roles(
roles=["support-viewer"], usernames=["onboarding-user"]
)
Replace the example expiry with a future ISO 8601 timestamp that matches the
intended access window. To make an assignment permanent, leave out
expires_at.
/api/assign/roles/curl -X POST "$TARUVI_SITE_URL/api/assign/roles/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
"roles": [
"$TARUVI_ROLE_SLUG"
],
"usernames": [
"$TARUVI_USERNAME"
]
}
JSON
200
/api/revoke/roles/curl -X DELETE "$TARUVI_SITE_URL/api/revoke/roles/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
"roles": [
"$TARUVI_ROLE_SLUG"
],
"usernames": [
"$TARUVI_USERNAME"
]
}
JSON
200
Assignment can return HTTP 200 with data.failures for individual username
and role pairs. Revocation can also return HTTP 200 with data.failures.
Successful pairs remain applied in either partial result. Re-read the user's
roles and app access, record each failed username and role, correct the
selected site, slug, username, or expiry, then retry only those failed pairs.
The JavaScript SDK declares RolesResponse data as {count: number},
but that type does not match either backend response. Full success contains
status and message with no data; a partial result contains
data.failures and no count. Treat the result as unknown
and check its shape at runtime instead of trusting the declared data type:
type RoleFailure = {username: string; role: string; error: string};
function isRoleFailure(value: unknown): value is RoleFailure {
if (typeof value !== "object" || value === null) return false;
const candidate = value as Partial<RoleFailure>;
return (
typeof candidate.username === "string" &&
typeof candidate.role === "string" &&
typeof candidate.error === "string"
);
}
function roleFailures(response: unknown): RoleFailure[] {
if (typeof response !== "object" || response === null) return [];
const data = (response as {data?: unknown}).data;
if (typeof data !== "object" || data === null) return [];
const failures = (data as {failures?: unknown}).failures;
return Array.isArray(failures) ? failures.filter(isRoleFailure) : [];
}
Pass each assignment or revocation result to roleFailures as unknown. An
empty failure list means success only when the response also has the success
message. Don't read a count from the JavaScript SDK type.
For other problems, see troubleshooting.
Verify active access
Re-read the user and available apps after an assignment:
import {User} from '@taruvi/sdk';
const users = new User(taruvi);
const userAfterAssignment = await users.getUser("temporary-user");
const appsAfterAssignment = await users.getUserApps("temporary-user");
user_after_assignment = client.users.get("temporary-user")
apps_after_assignment = client.users.apps("temporary-user")
Confirm the expected role appears in the user read and the expected app appears
in the app read. After expires_at, repeat both reads and confirm the expired
membership no longer contributes roles or app access. Refine providers 1.3.6
can read roles and apps; getMany and custom operations aren't supported.
/api/users/$TARUVI_USERNAME/apps/curl "$TARUVI_SITE_URL/api/users/$TARUVI_USERNAME/apps/" \
-H "Authorization: Api-Key $TARUVI_API_KEY"
200
Assigning a role doesn't guarantee the user can do what you expect. Use Test access decisions to check an allowed case and a denied case for the intended resource and action.