-
Notifications
You must be signed in to change notification settings - Fork 1
fix: Use PRIVATE-TOKEN header for PAT authentication instead of Bearer #187
Description
Problem
Currently, the server always uses Authorization: Bearer <token> for all authentication types (both PAT and OAuth tokens). While GitLab accepts Bearer for PATs in most cases, the canonical header for Personal Access Tokens is PRIVATE-TOKEN.
Current behavior
In src/utils/fetch.ts:187 (getAuthorizationHeader()):
export function getAuthorizationHeader(): string | undefined {
const token = getGitLabToken();
return token ? `Bearer ${token}` : undefined;
}In src/services/ConnectionManager.ts:62:
const clientOptions = oauthMode
? {}
: { headers: { Authorization: `Bearer ${GITLAB_TOKEN}` } };Both always use Bearer regardless of token type.
Expected behavior
- Static mode (PAT): Use
PRIVATE-TOKEN: <token>header - OAuth mode: Use
Authorization: Bearer <token>header
Why this matters
PRIVATE-TOKENis GitLab's canonical header for PATs and is guaranteed to work across all API surfaces (REST, GraphQL)- Some edge cases with newer token formats (rotating tokens, tokens with dots) may behave differently with Bearer
- Better alignment with GitLab's own documentation and best practices
- Clearer separation of authentication mechanisms
Proposed fix
Update getAuthorizationHeader() in src/utils/fetch.ts to return the appropriate header based on auth mode:
export function getAuthHeaders(): Record<string, string> {
const token = getGitLabToken();
if (!token) return {};
if (isOAuthEnabled()) {
return { Authorization: `Bearer ${token}` };
}
return { "PRIVATE-TOKEN": token };
}Update ConnectionManager.ts similarly for the GraphQL client initialization.
Files to modify
src/utils/fetch.ts-getAuthorizationHeader()->getAuthHeaders()src/services/ConnectionManager.ts- Client options constructionsrc/graphql/client.ts- Header merging (if needed)- Related tests
Additional context
Discovered when a user with a read_user-only scoped token got 401 on GraphQL but 200 on REST. While the root cause was insufficient scopes (docs correctly require api), investigating revealed the auth header type mismatch.