Handling various token formats in the package API
<!-- triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION -->
*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.*
<!-- triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION -->
## Problem
As we expand GitLab's package registry offering to more and more package management systems, we increasingly find that each system has a different way of handling authentication and credentials.
Users have requested a variety of ways to authenticate with these package managers: [Personal Access Tokens](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html), [Deploy Tokens](https://docs.gitlab.com/ee/user/project/deploy_tokens/), and [Job Tokens](https://docs.gitlab.com/ee/user/project/new_ci_build_permissions_model.html#job-token).
Each of these token types are set up with a different use case in mind, and generally use their own unique headers, which allows the auth flow to understand which authentication method and credentials it is working with. The problem is that package managers are often not configurable to include custom headers. For example, NPM will send all requests with a `Authorization: Bearer <token>` (Oauth) header.
This causes a conflict between keeping tokens for separate functions while allowing users to use all tokens in the same way (with the same headers).
In terms of code, in the API we see
```
def find_user_from_sources
find_user_from_access_token ||
find_user_from_job_token ||
find_user_from_warden
end
```
First we check to see if a PAT is present, then check for a job token, and last we check for warden auth. In the case of NPM, however, we are passing a PAT in without the standard PAT headers, so we needed to update `find_user_from_access_token` to also check for Oauth formatting, which is a bit hacky. Then for other package managers, we have overwritten methods that occur in [`auth_finders.rb`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/auth/auth_finders.rb) (see [here]( https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/api/helpers/packages/conan/api_helpers.rb#L144) and [here](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/api/helpers/packages_manager_clients_helpers.rb) for examples). This creates complexity that contributes to difficulty in tracing the auth flow for any given package manager, and in the case that we want to add a new auth method (deploy tokens for example), it is difficult to understand each type of auth that needs to be updated and where.
## Proposal
There is no way to avoid having to deal with these varying auth workflows, so I think it would be best if we at least were able to group all of the overrides and additional logic in one module. I think this is starting to come together already in `API::Helpers::Packages` with `BasicAuthHelpers`, but there is still other logic that lives in `ConanToken`, `Conan::ApiHelpers`, and in `Gitlab::Auth::AuthFinders`. The last example has an especially difficult to see npm-specific functionality where (https://gitlab.com/gitlab-org/gitlab/-/blob/ad2cc99686f75260f11cde8edab9b1f7d4baf254/lib/gitlab/auth/auth_finders.rb#L148) is where the PAT is checked with OAuth headers.
Outside of bringing this logic into a common namespace, I think it's worth discussing to see if there are maybe other ideas of how this could be organized in a discoverable and expandable way.
## Additional notes
Current understanding of the auth for each package manager:
Package Manager | Auth setup
--------|-------
NPM | Oauth format headers `Authorization: Bearer <token>`
Maven | Customizeable headers in `settings.xml`, docs currently use `Private-Token` header, we could potentially use Basic auth headers here to allow for username and password?
Conan | Authorization request is made with basic auth, then GitLab returns an encoded JWT that is used for subsequent requests. This could be modified to handle deploy tokens
Nuget | Basic auth - un/pw
PyPI | Basic auth - un/pw
GoProxy | `.netrc` file that uses basic auth headers
Composer | Oauth format headers `Authorization: Bearer <token>`
## References
- [GitLab API Authentication docs](https://docs.gitlab.com/ee/api/#authentication)
## Work progress
Package Manager | MR
--------|-------
NPM |
Maven |
Conan |
Nuget | :white_check_mark: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627
PyPI |
GoProxy |
Composer |
epic