Create grant
Bind a user or team to project.viewer, project.editor, or
project.admin on the project identified by the project-id header.
Name the principal with user (user_id or identifier) or team
(team_id or name). IDs are asgn_<opaque>. Owning-team
(project.team) grants are not created here — claim owns that path. An
unrevoked grant with the same principal and relation occupies the unique
key even after expires_at; DELETE it before re-creating.
Create does not accept expand. The user_id and team locators
return 201, whose user / team carry only user_id / team_id,
and still 404 / 409 when the principal is missing or the tuple
already exists. Creating by user.identifier answers 202 with no
body on every outcome. Granting the session caller's own user is
grant.invalid on either user locator. Read the grant back for
identifier and display.
Accepts either a project secret (oauth2) or a user-bound Console
session cookie (sessionCookie). Session callers are authorized as
the human against the target project (home may differ). Cookie-authenticated
requests follow the scheme's CSRF rules (sessionCookie).
AuthorizationBearer <token>Scope: project.write
project_id*stringThe unique identifier of the project
^[a-zA-Z0-9_-]+$application/json- body
Bind a user or a team. Exactly one of user or team. Shared fields are
relation and optional expires_at. Sending both locators or neither is
grant.invalid.
relation*stringCatalog relation on object_type project. team (owning-team) is not allowed.
"viewer""editor""admin"expires_at?stringOptional expiry. Must be in the future when set. Expiry stops authorization but does not free the unique binding; DELETE the grant before posting the same principal and relation again.
date-timeuser?User to bind. Exactly one of user_id or identifier. The user must
exist in the platform project when a platform project is configured.
Mutually exclusive with team.
team?Team to bind. Exactly one of team_id or name. The team must exist
in the platform project when a platform project is configured.
Mutually exclusive with user.
The grant was created. Returned for the user.user_id and team
locators only.
application/json- response
A collaboration grant binding a user or a team to a project relation.
Discriminate on which of user or team is present. Those objects are
always refs (user_id / team_id); expand adds extra fields on the same
object rather than a sibling.
id*stringManaged assignment id (asgn_<opaque>).
project_id*stringProject this grant is scoped to.
object_type*"project"Catalog object type. Always project for this API.
"project"relation*stringCatalog relation on the project.
"viewer""editor""admin"created_at*stringWhen the grant was created.
date-timeexpires_at?|When the grant expires. Null when it does not expire. GET still returns expired unrevoked grants; authorization ignores them.
user?Present on a user grant. Omit on a team grant. Always a user-ref
(user_id); expand adds envelope fields on this same object.
team?Present on a team grant. Omit on a user grant. Always a team-ref
(team_id); expand adds envelope fields on this same object.
import { configureZitadel, getApi } from "@zitadel/api/config";import { setApiCsrfToken } from "@zitadel/api/runtime/auth";// In the browser, through the SDK proxy: the session cookie authenticates the call.const client = getApi(configureZitadel({ projectId: "proj_01KWH1P4MYS7F0N9WD3P2E4YM5" }));// A write the session cookie authenticates carries the session's CSRF token.setApiCsrfToken((await client.getMySessionCsrfToken()).csrf_token);const grant = await client.createGrant({ relation: "viewer" }, { project_id: "proj_01KWH1P4MYS7F0N9WD3P2E4YM5" });{ "id": "string", "project_id": "string", "object_type": "project", "relation": "viewer", "created_at": "2019-08-24T14:15:22Z", "expires_at": "2019-08-24T14:15:22Z", "user": { "user_id": "string", "identifier": "string", "identifier_property": "string", "display": "string", "schema": "string", "attributes": {}, "metadata": { "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z", "status": "active", "lifecycle_owner_team_id": "string", "lifecycle_owner_team": { "id": "string", "name": "string", "status": "active", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } } }, "team": { "team_id": "string", "name": "string", "status": "active", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }}Was this helpful?