# Explicit permissions API

Sourcegraph exposes an HTTP API that allows site admins to explicitly set repository permissions. This is an alternative to other mechanisms, which involve directly talking to the code host.

The API is a [Connect RPC](https://connectrpc.com/) service that speaks JSON over HTTP. All procedures are served as `POST` requests under the `/api/` path prefix on your Sourcegraph instance.

> NOTE: A legacy GraphQL API (`setRepositoryPermissionsForUsers`, `setRepositoryPermissionsUnrestricted`, `setSubRepositoryPermissionsForUsers`, `authorizedUserRepositories`, etc.) previously served this use case and is still available for backwards compatibility, but the HTTP API documented on this page is the recommended interface for all new integrations.

## Permissions mechanisms in parallel

If you want to use explicit permissions management alongside permissions synchronised from code hosts, read section [permission mechanisms in parallel here](/admin/permissions/#permissions-mechanisms-in-parallel).

## Recommendations

We only recommend to use the explicit permissions API in cases where the other methods are not possible or effective.
E.g. if a code host does not support permission syncing/webhooks or if it would take an unreasonable amount of resources/time to sync permissions from the code host.

It's also a good idea to use the explicit permissions API if the source of truth for the code host permissions is already defined in some external system, e.g. LDAP group membership.
In that case, it might be less resource intensive to sync the permissions from the external source of truth directly via a periodically running routine.

## SLA

Sourcegraph SLA is that **p95 of write requests to the explicit permissions API will be resolved within 10 seconds**.

Sourcegraph does not provide an SLA for how fresh the permissions are, since the data is provided as is to the API.

## Disadvantages

It is important to note that when using the explicit permissions API, the permissions are written to the database as provided, without further verification that such permissions do exist on the code host side.

Keeping the permissions in sync and fresh is the responsibility of the site admins.

## Configuration

To enable the permissions API, add the following to the [site configuration](/admin/config/site-config):

```json
"permissions.userMapping": {
    "enabled": true,
    "bindID": "username"
}
```

The `bindID` value specifies how to uniquely identify users when setting permissions:

-   `username`: You can set permissions for users by specifying their Sourcegraph usernames. Using usernames is **preferred**, as usernames are required to be unique for each user.
-   `email`: You can set permissions for users by specifying their email addresses (which must be verified primary emails associated with their Sourcegraph user account). This method can lead to unexpected results if there are multiple Sourcegraph user accounts with the same verified email address. Also, the email address is case-sensitive, so it should be exactly the same as set on the Sourcegraph UI.

After you enable the permissions API, you must use the API described below to allow users to view repositories (site admins bypass all permissions checks and can always view all repositories).

> NOTE: If you were previously using [permissions syncing](/admin/permissions/syncing), e.g. syncing permissions from GitHub, then those permissions are used as the initial state after enabling explicit permissions. Otherwise, the initial state is for all repositories to have an empty set of authorized users, so users will not be able to view any repositories.

> NOTE: In some cases, in order for the repo permissions to be enforced, you must re-save the code host connection configuration with some modification to the JSON after enabling the permissions API.

Use of the explicit permissions API also requires the **Explicit Permissions API** license feature to be enabled on the instance. Without it, calls to the API will fail with a `FailedPrecondition` error.

## API overview

The explicit permissions HTTP API is a Connect RPC service. All procedures are HTTP `POST` requests with JSON request and response bodies, served under `/api/` on your Sourcegraph instance:

| Procedure | Path |
| --- | --- |
| `GetExplicitRepoPermission` | `/api/explicitrepopermissions.v1.Service/GetExplicitRepoPermission` |
| `ListExplicitRepoPermissions` | `/api/explicitrepopermissions.v1.Service/ListExplicitRepoPermissions` |
| `CreateExplicitRepoPermission` | `/api/explicitrepopermissions.v1.Service/CreateExplicitRepoPermission` |
| `DeleteExplicitRepoPermission` | `/api/explicitrepopermissions.v1.Service/DeleteExplicitRepoPermission` |

A machine-readable OpenAPI schema is served at `/api/openapi.yaml` and can be used to generate clients or to explore the API in tools such as Swagger UI.

> NOTE: This API is distinct from the legacy GraphQL endpoint at `/.api/graphql`. They are served on different path prefixes and have different authentication requirements.

### Resource names

Resources are identified by string [resource names](https://google.aip.dev/122) rather than opaque GraphQL node IDs:

| Resource | Format | Example |
| --- | --- | --- |
| Repository | `repositories/{numeric_id}` | `repositories/123` |
| User (by numeric ID) | `users/{numeric_id}` | `users/456` |
| User (by username) | `users/@{username}` | `users/@alice` |
| User (by email) | `users/{email}` | `users/alice@example.com` |
| Explicit repo permission | `repositories/{repo_id}/explicitRepoPermissions/{user}` | `repositories/123/explicitRepoPermissions/@alice` |

The `{user}` segment of an explicit repo permission name accepts the same formats as the user resource (numeric ID, `@username`, or email), in line with the `bindID` configured on the instance.

### Content type and encoding

The default encoding is JSON. Requests should be sent with `Content-Type: application/json`. Protobuf encoding is also supported by setting `Content-Type: application/proto`; the examples on this page use JSON.

### Authentication

The HTTP API only accepts **token-based authentication** — session cookies are not accepted (this differs from the legacy `/.api/graphql` endpoint). Provide a Sourcegraph access token using the standard `Authorization: Bearer <token>` header. OAuth tokens and HTTP-header authentication are also supported.

```bash
curl -X POST \
  -H "Authorization: Bearer $SRC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  https://sourcegraph.example.com/api/explicitrepopermissions.v1.Service/ListExplicitRepoPermissions \
  -d '{"parent": "repositories/123"}'
```

#### Token scopes

Access tokens used with the HTTP API should use the fine-grained external API scopes:

| Operation | Required scope |
| --- | --- |
| `GetExplicitRepoPermission`, `ListExplicitRepoPermissions` | `externalapi:read` |
| `CreateExplicitRepoPermission`, `DeleteExplicitRepoPermission` | `externalapi:write` |

Legacy `user:all` tokens are still accepted but every use is audit-logged. We recommend issuing scoped tokens for all new integrations.

#### RBAC

In addition to a valid token, the calling user must hold the corresponding RBAC permission on the instance:

| Operation | Required RBAC permission |
| --- | --- |
| Reads (`Get`, `List`) | `REPO_PERMISSIONS#READ` |
| Writes (`Create`, `Delete`) | `REPO_PERMISSIONS#WRITE` |

This replaces the broad site-admin / `user:all` check used by the legacy GraphQL mutations.

## Procedures

### `CreateExplicitRepoPermission`

Grants a user explicit access to a repository.

The `parent` field may be either a repository or a user, and the nested `explicit_repo_permission` provides the other side of the relationship.

Grant `alice` access to repository `123` (parent is a repo):

```bash
curl -X POST \
  -H "Authorization: Bearer $SRC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  https://sourcegraph.example.com/api/explicitrepopermissions.v1.Service/CreateExplicitRepoPermission \
  -d '{
    "parent": "repositories/123",
    "explicit_repo_permission": { "user": "users/@alice" }
  }'
```

Equivalently, grant `alice` access to repository `123` with the user as the parent:

```bash
curl -X POST \
  -H "Authorization: Bearer $SRC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  https://sourcegraph.example.com/api/explicitrepopermissions.v1.Service/CreateExplicitRepoPermission \
  -d '{
    "parent": "users/@alice",
    "explicit_repo_permission": { "repository": "repositories/123" }
  }'
```

Response:

```json
{
  "name": "repositories/123/explicitRepoPermissions/456",
  "user": "users/456",
  "repository": "repositories/123"
}
```

### `GetExplicitRepoPermission`

Looks up a single explicit permission by its resource name.

```bash
curl -X POST \
  -H "Authorization: Bearer $SRC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  https://sourcegraph.example.com/api/explicitrepopermissions.v1.Service/GetExplicitRepoPermission \
  -d '{
    "name": "repositories/123/explicitRepoPermissions/@alice"
  }'
```

Response:

```json
{
  "name": "repositories/123/explicitRepoPermissions/456",
  "user": "users/456",
  "repository": "repositories/123"
}
```

### `ListExplicitRepoPermissions`

Lists explicit permissions, scoped by a `parent` resource. The parent may be either a repository (to list all users with explicit access to that repo) or a user (to list all repos that user has been explicitly granted). Results are paginated with `page_size` and `page_token`.

List all users with explicit access to repository `123`:

```bash
curl -X POST \
  -H "Authorization: Bearer $SRC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  https://sourcegraph.example.com/api/explicitrepopermissions.v1.Service/ListExplicitRepoPermissions \
  -d '{
    "parent": "repositories/123",
    "page_size": 50,
    "page_token": ""
  }'
```

List all repositories that `alice` has explicit access to:

```bash
curl -X POST \
  -H "Authorization: Bearer $SRC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  https://sourcegraph.example.com/api/explicitrepopermissions.v1.Service/ListExplicitRepoPermissions \
  -d '{
    "parent": "users/@alice",
    "page_size": 50
  }'
```

Response:

```json
{
  "explicit_repo_permissions": [
    {
      "name": "repositories/123/explicitRepoPermissions/456",
      "user": "users/456",
      "repository": "repositories/123"
    }
  ],
  "next_page_token": ""
}
```

If `next_page_token` is non-empty, pass it as `page_token` in a subsequent request to fetch the next page.

### `DeleteExplicitRepoPermission`

Revokes a user's explicit access to a repository.

```bash
curl -X POST \
  -H "Authorization: Bearer $SRC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  https://sourcegraph.example.com/api/explicitrepopermissions.v1.Service/DeleteExplicitRepoPermission \
  -d '{
    "name": "repositories/123/explicitRepoPermissions/@alice"
  }'
```

Response:

```json
{}
```

## Setting a repository as unrestricted

> NOTE: This capability is **not yet available in the new external HTTP API** and must still be performed via the legacy GraphQL API.

A repository can be marked as `unrestricted`, meaning it is visible to **all** Sourcegraph users regardless of any explicit permissions or permissions synced from a code host. Marking a repository as unrestricted disregards any previously set explicit or synced permissions for that repository for as long as the flag is set. Setting `unrestricted` back to `false` restores the previous permissions behaviour (explicit and/or synced permissions take effect again).

Use the GraphQL mutation below against `/.api/graphql`:

```graphql
mutation {
  setRepositoryPermissionsUnrestricted(
    repositories: ["<repo ID>", "<repo ID>", "<repo ID>"]
    unrestricted: true
  )
}
```

## Setting sub-repository permissions for users

> NOTE: Sub-repository permissions are **experimental** and are **not yet available in the new external HTTP API** — they must still be configured via the legacy GraphQL API.

Sub-repository permissions allow site admins to grant or deny a user access to specific files or directories *within* a repository, in addition to the repository-level access controls described above.

To enable the feature, add the following to the [site configuration](/admin/config/site-config):

```json
"experimentalFeatures": {
  "subRepoPermissions": {
    "enabled": true
  }
}
```

Paths are specified using [glob](https://en.wikipedia.org/wiki/Glob_(programming)) syntax with the following rules:

- A path prefixed with `-` **denies** access to the matching files or directories.
- Permissions apply **in order**: later entries override earlier ones for paths they match.
- The **default** for any path that is not explicitly matched is to **deny** access.

> NOTE: A user that has general access to a repository but for whom **no** sub-repository permissions have been set can access the **entire** repository. Sub-repository permissions only take effect once at least one rule is configured for that user/repository pair.

Deny access to all paths in a repository **except** `README.md`:

```graphql
mutation {
  setSubRepositoryPermissionsForUsers(
    repository: "<repo ID>"
    userPermissions: [{bindID: "alice", paths: ["-/**", "/README.md"]}]
  ) {
    alwaysNil
  }
}
```

Allow access to all paths in a repository **except** `README.md`:

```graphql
mutation {
  setSubRepositoryPermissionsForUsers(
    repository: "<repo ID>"
    userPermissions: [{bindID: "alice", paths: ["/**", "-/README.md"]}]
  ) {
    alwaysNil
  }
}
```

## Migrating from the GraphQL API

If you previously integrated against the legacy GraphQL mutations and queries — for example `setRepositoryPermissionsForUsers`, `setRepositoryPermissionsUnrestricted`, `setSubRepositoryPermissionsForUsers`, or `authorizedUserRepositories` — the table below summarises the equivalent HTTP API calls.

| Legacy GraphQL | HTTP API |
| --- | --- |
| `setRepositoryPermissionsForUsers` (add a user) | `CreateExplicitRepoPermission` |
| `setRepositoryPermissionsForUsers` (remove a user) | `DeleteExplicitRepoPermission` |
| `authorizedUserRepositories` | `ListExplicitRepoPermissions` with `parent: "users/@<username>"` |
| Listing users for a repo | `ListExplicitRepoPermissions` with `parent: "repositories/<id>"` |

A minimal legacy GraphQL mutation looked like this:

```graphql
mutation {
	setRepositoryPermissionsForUsers(
		repository: "<repo ID>"
		userPermissions: [{bindID: "alice"}, {bindID: "bob"}]
	) {
		alwaysNil
	}
}
```

The equivalent using the HTTP API is one `CreateExplicitRepoPermission` call per user (and a `DeleteExplicitRepoPermission` call per user being removed), as shown in the [Procedures](#procedures) section above.

Notable differences:

- **Transport.** Connect RPC JSON over `POST /api/...` instead of GraphQL over `/.api/graphql`.
- **Authentication.** Access tokens only — no session cookies — with fine-grained `externalapi:read` / `externalapi:write` scopes and `REPO_PERMISSIONS#READ` / `#WRITE` RBAC, instead of a broad site-admin / `user:all` check.
- **Resource model.** CRUD over individual `ExplicitRepoPermission` resources with stable [AIP-style](https://google.aip.dev/122) resource names and pagination, instead of bulk set-style mutations that replace the entire ACL for a repository in one call.
- **Identifiers.** Numeric repo and user IDs (e.g. `repositories/123`) or human-readable user identifiers (`users/@alice`, `users/alice@example.com`) instead of opaque GraphQL node IDs.
