Docs

Create grant

POST
/grants

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).

Authorization

headerAuthorizationBearer <token>

Scope: project.write

Query Parameters

project_id*string

The unique identifier of the project

Match^[a-zA-Z0-9_-]+$

Request Body

application/json
  1. 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*string

Catalog relation on object_type project. team (owning-team) is not allowed.

Value in"viewer""editor""admin"
expires_at?string

Optional 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.

Formatdate-time
user?

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.

Response Body

The grant was created. Returned for the user.user_id and team locators only.

application/json
  1. 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*string

Managed assignment id (asgn_<opaque>).

project_id*string

Project this grant is scoped to.

object_type*"project"

Catalog object type. Always project for this API.

Value in"project"
relation*string

Catalog relation on the project.

Value in"viewer""editor""admin"
created_at*string

When the grant was created.

Formatdate-time
expires_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.

Example Request
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" });
Example Response
{  "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?