Fine-grained Personal Access Tokens
### Problem Statement ##### Current State * **Overly Broad Permissions**: PATs currently operate with coarse-grained scopes like `read_api` or `api` that grant extensive access across GitLab's entire feature set, violating the principle of least privilege. * **Large Blast Radius**: When a PAT is compromised, attackers gain access to all resources the user can access across all groups and projects they're a member of, potentially exposing sensitive data and operations across an entire organization. * **Limited Resource Specificity**: Users cannot create tokens that are restricted to specific projects, groups, or resource types, forcing them to choose between functionality and security. * **Namespace-Wide Access**: PATs automatically inherit access to all groups and projects the user belongs to, with no mechanism to restrict token access to only necessary resources. ##### Impact Assessment * **Security Risk**: High blast radius from token compromise * **User Frustration**: Inability to create appropriately scoped tokens * **Operational Risk**: Over-privileged automation and integrations #### DRIs - **PM**: @NellyVahab - **EM**: @jpr0c - **Eng IC**: @alexbuijs - **UX/PDM**: @ipelaez1 ### Requirements and Goals See handbook page: https://internal.gitlab.com/handbook/engineering/development/sec/govern/authorization/ ### User Experience As a developer, I can: * Select between legacy or fine-grained PATs * Scope down the token by boundary (group / project) * Scope down the resource by permission by CRUD or verb * Presented so resource and permissions leans towards principle of least privilege As an administrator, I can: * Prohibit usage of legacy PATs against my top level namespace * View fine-grained permissions in the Credential Inventory ##### [Designs](https://gitlab.com/gitlab-org/gitlab/-/issues/554883) |[ Prototype](https://www.figma.com/make/UR218bSAFaHJG7mBXomTzp/Fine-grained--Personal-Access-Token?node-id=0-1&p=f&t=oQjCajpOdJJBQXcF-0&fullscreen=1) ### Success Metrics Outlined [here](https://gitlab.com/groups/gitlab-operating-model/-/epics/188) ### Not in scope * Fine-grained permissions for Service Accounts * Fine-grained permissions for OAuth * Deprecating the legacy or broad token * Duo chat suggestions for permissions ### Related documents * [Security Requirements](https://docs.google.com/document/d/1TBxojL5_dXNHOx8HfLPnnaSiKH3-IXvr5GUaBN3sFoE/edit?tab=t.0https://docs.google.com/document/d/1TBxojL5_dXNHOx8HfLPnnaSiKH3-IXvr5GUaBN3sFoE/edit?tab=t.0) > [!note] > > This page may contain information related to upcoming products, features and functionality. It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes. Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc. <details> <summary> ### _Original Proposal_ </summary> ### Proposal Access token of every kind, like Personal Access Tokens, OAuth Access Tokens, Deploy Token and alike are a constant security concern due to their broad access levels. A simple `read_api` access token of a Gitlab team member might for instance read any internal issue under `gitlab.com/gitlab-com` even if it's just intended to read issues from a specific public project. In order to have a really fine grained and auditable access control of tokens I'd like to propose to attach a allow list to every token issues.For a first iteration targeting the REST API the allow list should have the form of: ``` OPERATION PATH ``` Where `OPERATION` is one or many of the used HTTP methods `GET, POST, PUT, DELETE` or a `*` for all methods. `PATH` would be the path to the intended API endpoint (with wildcards) like `/projects/278964/issues` to allow access to the `gitlab.com/gitlab-org/gitlab` project's issues. So an allow list entry of: ``` GET,POST /projects/278964/issues ``` would limit the access token to only read existing and create new issues in `gitlab.com/gitlab-org/gitlab` but not edit or delete existing issues as `PUT` and `DELETE` are missing. Another example would be ``` GET /projects/278964/* ``` which would allow read access to all project resources exposed for `gitlab.com/gitlab-org/gitlab`. Having those allow lists would enable us to create very specific task-bound tokens with least privileged access to the resources needed. Also the allow list could be audited for overly permissive rules like ``` * * ``` which would be the current `api` scope granting full access on behalf of the user. </details>
epic