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 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.
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:
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, 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 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.
BASHcurl -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):
BASHcurl -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:
BASHcurl -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.
BASHcurl -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:
BASHcurl -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:
BASHcurl -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.
BASHcurl -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:
GRAPHQLmutation { 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:
JSON"experimentalFeatures": { "subRepoPermissions": { "enabled": true } }
Paths are specified using glob 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:
GRAPHQLmutation { setSubRepositoryPermissionsForUsers( repository: "<repo ID>" userPermissions: [{bindID: "alice", paths: ["-/**", "/README.md"]}] ) { alwaysNil } }
Allow access to all paths in a repository except README.md:
GRAPHQLmutation { 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:
GRAPHQLmutation { 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 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:writescopes andREPO_PERMISSIONS#READ/#WRITERBAC, instead of a broad site-admin /user:allcheck. - Resource model. CRUD over individual
ExplicitRepoPermissionresources with stable AIP-style 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.