> For the complete documentation index, see [llms.txt](https://docs.sonarsource.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sonarsource.com/sonarqube-cloud/administering-sonarcloud/managing-organization/scoped-organization-tokens-api-migration.md).

# Scoped Organization Tokens: API migration guide

SonarQube Cloud API migration guide for integrations that use POST /users/roles to grant permissions to Scoped Organization Tokens, now deprecated in favor of inline role assignments.

Use this guide if your integration creates Scoped Organization Tokens and assigns permissions using `POST /users/roles`. It shows the old and new API calls side by side for both organization-level and project-level permissions, so you can update each call in your integration.

The `POST /users/roles` endpoint, when used with `principalType: organizationToken`, is deprecated. If your integration calls this endpoint to grant organization or project permissions to a Scoped Organization Token (SOT), migrate to the current API, which assigns permissions inline during token creation.

> **Important:** `POST /users/roles` with `principalType: organizationToken` is deprecated and will be removed in a future release. Plan to migrate existing integrations.

This page covers what changed and how to update your API calls. For full endpoint reference, see the [Authentication domain API](https://api-docs.sonarsource.com/sonarqube-cloud/default/public-externalauthentication-0-0).

> **Note:** The token ID is the UUID returned in the `id` field of the creation response. It is distinct from the token value (the `token` field), which begins with `sqco_`. Use the token ID in API calls that reference the token; use the token value only to authenticate requests.

## Organization-level permissions

An organization-level role applies across the whole organization the token belongs to. No separate resource attachment is needed, since the token is already scoped to exactly one organization at creation time.

### Old API

In the old API, the `POST /authentication/token-definitions` endpoint had no `roleAssignments` field, so you created the token bare and granted the organization role in a separate call to `POST /users/roles`, with `resourceId` set to the organization's own UUID.

Step 1: Create the token.

`POST /authentication/token-definitions`

Request:

```http
{
  "name": "<YourTokenName>",
  "organizationId": "<YourOrganizationUUID>",
  "expiresAt": "<YourExpiryDate>"
}
```

Response:

```http
{
  "id": "<YourTokenUUID>",
  "name": "<YourTokenName>",
  "description": "",
  "token": "<YourTokenValue>",
  "organizationId": "<YourOrganizationUUID>",
  "createdAt": "<CreationTimestamp>",
  "expiresAt": "<YourExpiryDate>"
}
```

Step 2: Assign the organization role.

`POST /users/roles`

Request:

```http
{
  "principalId": "<YourTokenUUID>",
  "principalType": "organizationToken",
  "resourceType": "organization",
  "resourceId": "<YourOrganizationUUID>",
  "role": "scan"
}
```

Response:

```http
{
  "id": "<YourRoleAssignmentUUID>",
  "principalId": "<YourTokenUUID>",
  "principalType": "organizationToken",
  "resourceType": "organization",
  "resourceId": "<YourOrganizationUUID>",
  "role": "scan"
}
```

`POST /users/roles` with `principalType: organizationToken` is now deprecated in favor of the new format below.

### New API

`roleAssignments` now carries the role directly. For an organization-level role, the creation call is the entire grant. No second call is needed, since the token is already tied to one organization via `organizationId`.

`POST /authentication/token-definitions`

Request:

```http
{
  "name": "<YourTokenName>",
  "organizationId": "<YourOrganizationUUID>",
  "expiresAt": "<YourExpiryDate>",
  "roleAssignments": [
    {
      "resourceType": "organization",
      "roles": ["scan"]
    }
  ],
  "autoGrantProjectPermissions": false
}
```

Response:

```http
{
  "id": "<YourTokenUUID>",
  "name": "<YourTokenName>",
  "description": "",
  "token": "<YourTokenValue>",
  "organizationId": "<YourOrganizationUUID>",
  "createdAt": "<CreationTimestamp>",
  "expiresAt": "<YourExpiryDate>",
  "roleAssignments": [
    {
      "resourceType": "organization",
      "roles": ["scan"]
    }
  ],
  "autoGrantProjectPermissions": false
}
```

That's it. There is one call, *no second step*. The token now has scan across the organization.

## Project-level permissions

A project-level role only applies once the token is attached to a specific project. In the old API, a single `POST /users/roles` call both granted the role and bound it to one project. In the new API, these are two separate steps: you declare the role at creation time, then attach each project.

### Old API

In the old API, you created the token bare, then granted the project role in a separate call to `POST /users/roles` for each project.

Step 1: Create the token.

`POST /authentication/token-definitions`

Request:

```http
{
  "name": "<YourTokenName>",
  "organizationId": "<YourOrganizationUUID>",
  "expiresAt": "<YourExpiryDate>"
}
```

Response:

```http
{
  "id": "<YourTokenUUID>",
  "name": "<YourTokenName>",
  "description": "",
  "token": "<YourTokenValue>",
  "organizationId": "<YourOrganizationUUID>",
  "createdAt": "<CreationTimestamp>",
  "expiresAt": "<YourExpiryDate>"
}
```

At this point, the token has no permission anywhere.

Step 2: Assign the project role. Repeat for each project.

`POST /users/roles`

Request:

```http
{
  "principalId": "<YourTokenUUID>",
  "principalType": "organizationToken",
  "resourceType": "project",
  "resourceId": "<YourProjectUUID>",
  "role": "scan"
}
```

Response:

```http
{
  "id": "<YourRoleAssignmentUUID>",
  "principalId": "<YourTokenUUID>",
  "principalType": "organizationToken",
  "resourceType": "project",
  "resourceId": "<YourProjectUUID>",
  "role": "scan"
}
```

This call binds one role to one project. Every additional role (e.g. `user` alongside `scan`) and every additional project needs its own `POST /users/roles` call; granting two roles on ten projects is 20 calls, not 10.

`POST /users/roles` for `principalType: organizationToken` is now deprecated in favor of the new format below.

### New API

`roleAssignments` declares the role at creation time. A separate call to `POST /authentication/token-resource-links` attaches the token to each project, without repeating the role.

Step 1: Create the token with the project-level role.

`POST /authentication/token-definitions`

Request:

```http
{
  "name": "<YourTokenName>",
  "organizationId": "<YourOrganizationUUID>",
  "expiresAt": "<YourExpiryDate>",
  "roleAssignments": [
    {
      "resourceType": "project",
      "roles": ["scan"]
    }
  ],
  "autoGrantProjectPermissions": false
}
```

Response:

```http
{
  "id": "<YourTokenUUID>",
  "name": "<YourTokenName>",
  "description": "",
  "token": "<YourTokenValue>",
  "organizationId": "<YourOrganizationUUID>",
  "createdAt": "<CreationTimestamp>",
  "expiresAt": "<YourExpiryDate>",
  "roleAssignments": [
    {
      "resourceType": "project",
      "roles": ["scan"]
    }
  ],
  "autoGrantProjectPermissions": false
}
```

`roleAssignments` declares what role the token holds on any project it's attached to, but it doesn't grant access to a project yet. That happens in step 2.

Step 2: Attach each project. Repeat for each project.

`POST /authentication/token-resource-links`

Request:

```http
{
  "organizationTokenId": "<YourTokenUUID>",
  "resourceType": "project",
  "resourceId": "<YourProjectUUID>"
}
```

Response:

```http
{
  "id": "<YourResourceLinkUUID>",
  "organizationTokenId": "<YourTokenUUID>",
  "resourceType": "project",
  "resourceId": "<YourProjectUUID>"
}
```

There's no `role` field in this call: the token declared `scan` in step 1. Attaching the token to another project is one more call to this endpoint, regardless of how many roles the token holds.

## Retrieving a token's permissions

In the old API, the token definition and its roles were separate: `GET /authentication/token-definitions/{id}` returned no role information. In the new API, the token definition includes `roleAssignments` directly.

### Organization role

Old API: `GET /authentication/token-definitions/{id}` does not return role information. Call `GET /users/roles?principalIds=<YourTokenUUID>&principalType=organizationToken&resourceType=organization` to retrieve it.

```http
{
  "roles": [
    {
      "id": "<YourRoleAssignmentUUID>",
      "principalId": "<YourTokenUUID>",
      "principalType": "organizationToken",
      "resourceType": "organization",
      "resourceId": "<YourOrganizationUUID>",
      "role": "scan"
    }
  ]
}
```

New API: `GET /authentication/token-definitions/{id}` now includes a `roleAssignments` field that lists the token's assigned roles (organization and project) directly in the response.

```http
{
  "id": "<YourTokenUUID>",
  "name": "<YourTokenName>",
  "description": "",
  "organizationId": "<YourOrganizationUUID>",
  "createdAt": "<CreationTimestamp>",
  "expiresAt": "<YourExpiryDate>",
  "lastUsedAt": null,
  "roleAssignments": [
    {
      "resourceType": "organization",
      "roles": ["scan"]
    }
  ],
  "autoGrantProjectPermissions": false
}
```

### Project roles and accessible projects

Old API: a single call, `GET /users/roles?principalIds=<YourTokenUUID>&principalType=organizationToken&resourceType=project`, returns both the token's project roles and the projects it can access, since each row already ties one role to one project.

```http
{
  "roles": [
    {
      "id": "<YourRoleAssignmentUUID>",
      "principalId": "<YourTokenUUID>",
      "principalType": "organizationToken",
      "resourceType": "project",
      "resourceId": "<YourProjectUUID>",
      "role": "scan"
    }
  ]
}
```

Each role-project combination is its own row. A token with `scan` on five projects returns five rows here, each independently trackable by its own `id`.

New API: this splits into two calls, matching the two-step grant described in [Project-level permissions](#project-level-permissions).

`GET /authentication/token-definitions/{id}` includes a `roleAssignments` field that lists the token's declared project roles.

```http
{
  "id": "<YourTokenUUID>",
  "name": "<YourTokenName>",
  "description": "",
  "organizationId": "<YourOrganizationUUID>",
  "createdAt": "<CreationTimestamp>",
  "expiresAt": "<YourExpiryDate>",
  "lastUsedAt": null,
  "roleAssignments": [
    {
      "resourceType": "project",
      "roles": ["scan"]
    }
  ],
  "autoGrantProjectPermissions": false
}
```

`GET /authentication/token-resource-links?organizationTokenId=<YourTokenUUID>` lists the projects those roles are attached to.

```http
{
  "tokenResourceLinks": [
    {
      "id": "<YourResourceLinkUUID>",
      "organizationTokenId": "<YourTokenUUID>",
      "resourceType": "project",
      "resourceId": "<YourProjectUUID>"
    }
  ],
  "page": { "pageIndex": 1, "pageSize": 50, "total": 1 }
}
```

The roles declared in the first call apply to every project listed in the second. Attaching a sixth project doesn't repeat the role, it just adds one more entry to `tokenResourceLinks`.

## Summary

| Aspect                            | Old API                                                   | New API                                                         |
| --------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------- |
| Organization role assignment      | `POST /users/roles` (separate call)                       | `POST /authentication/token-definitions` with `roleAssignments` |
| Project role assignment           | `POST /users/roles` per project, per role                 | `POST /authentication/token-definitions` with `roleAssignments` |
| Attaching projects                | `POST /users/roles` per project                           | `POST /authentication/token-resource-links` per project         |
| Call count (R roles × N projects) | 1 creation + (R × N) role calls                           | 1 creation + N attachment calls                                 |
| Token definition response         | No role information                                       | Includes `roleAssignments`                                      |
| Retrieving accessible projects    | `GET /users/roles` with `principalType=organizationToken` | `GET /authentication/token-resource-links`                      |

## Related pages

* [Scoped Organization Tokens](/sonarqube-cloud/administering-sonarcloud/managing-organization/scoped-organization-tokens.md)
* [Web API](/sonarqube-cloud/appendices/web-api.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sonarsource.com/sonarqube-cloud/administering-sonarcloud/managing-organization/scoped-organization-tokens-api-migration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
