oauth_scopes config is ignored during web OAuth login; client always requests write_repository api
### Checklist - [X] I'm using the latest version of the extension (Run `glab --version`) - Extension version: _glab 1.100.0 (e345ca67)_ - [X] Operating system and version: _macOS Tahoe 26.3.1 (a) (25D771280a)_ - [X] Gitlab.com or self-managed instance? _self-managed instance_ - [X] GitLab version (if self-managed) _{"version":"18.11.4-ee","revision":"78d6b913cb5","kas":{"enabled":true,"externalUrl":"wss://git.drupalcode.org/-/kubernetes-agent/","externalK8sProxyUrl":"https://git.drupalcode.org/-/kubernetes-agent/k8s-proxy/","version":"18.11.4"},"enterprise":true}_ - [X] I have performed `glab auth status` to check for authentication issues - [X] Run the command in debug mode (like `DEBUG=true glab mr list`) and attach any useful output ### Summary When authenticating to a GitLab Self-Managed instance via the web OAuth flow (`glab auth login` → Web), glab ignores the configured `oauth_scopes` value and always requests the hardcoded default scopes (write_repository, api). This makes it impossible to obtain a read-only OAuth token, and causes a hard failure when authenticating against an OAuth application that is registered with read-only scopes only. A user explicitly configuring narrower scopes for least-privilege receives broader scopes in the request instead. Beyond the failure below, this is a security concern: it prevents read-only OAuth usage and silently escalates the requested permission set past what the user configured. ### Environment - OS: Darwin 25.3.0 arm64 - SHELL: /bin/zsh - TERM: xterm-256color - GLAB: glab 1.100.0 (e345ca67)% Other: N/A ### Steps to reproduce 1. On a GitLab Self-Managed instance, register an OAuth application (user-level) with only read-only scopes: openid, profile, read_user, read_api, read_repository. Confidential unchecked. Redirect URI http://localhost:7171/auth/redirect. 2. Configure glab to request a matching read-only scope set: ``` glab config set client_id <APP_ID> --host <self-managed-host> glab config set oauth_scopes "openid profile read_user read_api read_repository" --host <self-managed-host> ``` 3. Confirm the value is stored: ``` glab config get oauth_scopes --host <self-managed-host> # => openid profile read_user read_api read_repository ``` 4. Authenticate, selecting Web for the login method: ``` glab auth login --hostname <self-managed-host> ``` ### What is the current _bug_ behavior? The browser opens to an authorize URL whose scope parameter is not the configured value. It contains the hardcoded broad defaults instead: ``` .../oauth/authorize?client_id=...&scope=openid+profile+read_user+write_repository+api&... ``` Because the requested scopes (write_repository, api) exceed what the read-only OAuth app grants, GitLab rejects the request with: > An error has occurred — The requested scope is invalid, unknown, or malformed. Confirmed that adding `write_repository` and `api` scopes temporarily to the personal OAuth app restored the working behaviour. ### What is the expected _correct_ behavior? The authorize request should use the scopes configured via oauth_scopes, i.e. `scope=openid+profile+read_user+read_api+read_repository`, allowing a read-only OAuth token and successful authorization against a read-only-scoped app. ### Relevant logs and/or screenshots ![Screenshot_2026-05-30_at_11.25.33_PM](/uploads/9e5df5d6098b5faee517ac9dd9cc3655/Screenshot_2026-05-30_at_11.25.33_PM.png){width=390 height=533} ``` % glab config get oauth_scopes --host git.drupalcode.org openid profile read_user read_api read_repository % DEBUG=true glab auth login --hostname git.drupalcode.org [git remote -v] - Signing into git.drupalcode.org [open https://git.drupalcode.org/oauth/authorize?client_id=X&code_challenge=X&code_challenge_method=S256&redirect_uri=http%3A%2F%2Flocalhost%3A7171%2Fauth%2Fredirect&response_type=code&scope=openid+profile+read_user+write_repository+api&state=X] ``` ![Screenshot_2026-05-30_at_11.23.33_PM](/uploads/6fcf987af8bd9f5493aae1583f824c2a/Screenshot_2026-05-30_at_11.23.33_PM.png){width=635 height=199} ### Possible fixes I haven't traced the source, so this is a hypothesis rather than a confirmed location: the web OAuth login flow appears to use a hardcoded default scope list when constructing the `/oauth/authorize` request, rather than reading the per-host `oauth_scopes` configuration value. The fix would likely be to have the authorize-URL builder resolve scopes from the host config (`oauth_scopes`) when present, falling back to the default list only when unset — mirroring how `client_id` is already read per-host. Worth checking whether `oauth_scopes` is honored in the device/token flows but not the web flow, which would localize the gap.
issue