Skip to content

fix(auth): use PRIVATE-TOKEN header for PAT authentication instead of Bearer#189

Merged
polaz merged 2 commits intomainfrom
feat/#187-fix-use-private-token-header-for-pat-authenticatio
Jan 24, 2026
Merged

fix(auth): use PRIVATE-TOKEN header for PAT authentication instead of Bearer#189
polaz merged 2 commits intomainfrom
feat/#187-fix-use-private-token-header-for-pat-authenticatio

Conversation

@polaz
Copy link
Copy Markdown
Member

@polaz polaz commented Jan 24, 2026

Summary

  • Static (PAT) mode now uses GitLab's canonical PRIVATE-TOKEN header instead of Authorization: Bearer
  • OAuth mode continues to use Authorization: Bearer as before
  • Renamed getAuthorizationHeader() to getAuthHeaders() returning a header object based on auth mode

Test plan

  • All 3881 unit tests pass
  • ESLint: 0 errors
  • Build succeeds
  • Integration test with PAT against real GitLab instance
  • Verify OAuth mode still works with Bearer header

Closes #187

… Bearer

Static mode (PAT) now uses GitLab's canonical PRIVATE-TOKEN header.
OAuth mode continues to use Authorization: Bearer as before.

Closes #187
Copilot AI review requested due to automatic review settings January 24, 2026 17:59
@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 24, 2026

Test Coverage Report

Overall Coverage: 93.64%

Metric Percentage
Statements 93.14%
Branches 84.9%
Functions 82.94%
Lines 93.64%

View detailed coverage report

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes the authentication header format for Personal Access Tokens (PATs) to use GitLab's canonical PRIVATE-TOKEN header instead of Authorization: Bearer. OAuth mode continues to use Authorization: Bearer as expected.

Changes:

  • Renamed getAuthorizationHeader() to getAuthHeaders() returning header objects based on auth mode (PAT vs OAuth)
  • Updated ConnectionManager to use PRIVATE-TOKEN header for static/PAT mode
  • Updated all affected unit tests to expect PRIVATE-TOKEN instead of Authorization: Bearer in static mode

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/utils/fetch.ts Refactored authentication header logic to return appropriate headers based on auth mode (PRIVATE-TOKEN for PAT, Bearer for OAuth)
src/services/ConnectionManager.ts Updated GraphQL client initialization to use PRIVATE-TOKEN header in static/PAT mode
tests/unit/utils/fetch.test.ts Updated test assertions to expect PRIVATE-TOKEN header instead of Authorization Bearer
tests/unit/services/ConnectionManagerEnhanced.test.ts Updated test assertion to expect PRIVATE-TOKEN header in ConnectionManager initialization

Cover getAuthHeaders() for PAT, OAuth, and no-token scenarios.
Cover ConnectionManager OAuth mode initializing without static headers.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@polaz polaz merged commit 7799dde into main Jan 24, 2026
22 checks passed
@polaz polaz deleted the feat/#187-fix-use-private-token-header-for-pat-authenticatio branch January 24, 2026 18:10
sw-release-bot bot pushed a commit that referenced this pull request Jan 24, 2026
## [6.41.4](v6.41.3...v6.41.4) (2026-01-24)

### Bug Fixes

* **auth:** use PRIVATE-TOKEN header for PAT authentication instead of Bearer ([#189](#189)) ([7799dde](7799dde)), closes [#187](#187)
@sw-release-bot
Copy link
Copy Markdown

🎉 This PR is included in version 6.41.4 🎉

The release is available on:

Your semantic-release bot 📦🚀

polaz pushed a commit that referenced this pull request Jan 24, 2026
## [6.41.4](v6.41.3...v6.41.4) (2026-01-24)

### Bug Fixes

* **auth:** use PRIVATE-TOKEN header for PAT authentication instead of Bearer ([#189](#189)) ([7799dde](7799dde)), closes [#187](#187)
polaz added a commit that referenced this pull request Jan 24, 2026
* feat: detect token scopes at startup with graceful degradation (#188)

Add TokenScopeDetector service that calls /api/v4/personal_access_tokens/self
at startup to discover token scopes. Based on detected scopes:

- Skip GraphQL introspection when token lacks api/read_api (no 401 stack traces)
- Register only tools matching the token's permissions
- Show clean INFO messages with actionable fix URLs
- Warn when token expires within 7 days

Also adds comprehensive authentication documentation (docs/guide/authentication.md)
with PAT and OAuth walkthroughs, scope comparison table, and troubleshooting.
Links added across all installation/deployment docs.

* chore(release): 6.41.4 [skip ci]

## [6.41.4](v6.41.3...v6.41.4) (2026-01-24)

### Bug Fixes

* **auth:** use PRIVATE-TOKEN header for PAT authentication instead of Bearer ([#189](#189)) ([7799dde](7799dde)), closes [#187](#187)

* fix(auth): use enhancedFetch and UTC dates in token scope detection

- Replace global fetch with enhancedFetch in detectTokenScopes and
  detectVersionViaREST (respects timeouts, proxy, TLS settings)
- Parse expires_at as UTC date to avoid timezone off-by-one errors
- Use URL/URLSearchParams for proper encoding in getTokenCreationUrl
- Derive totalTools count dynamically from getToolScopeRequirements()
- Use jest.useFakeTimers() for deterministic expiry tests
- Test project/group token types, REST fallback, scope-gated paths

* fix(auth): deduplicate getTokenCreationUrl call, remove as-any casts

- Cache getTokenCreationUrl result in logTokenScopeInfo to avoid
  double URL construction
- Replace `as any` with proper GitLabScope[] type in test fixtures

* fix(token-scope): validate API response with Zod, remove manage_context from scope map

Replace unsafe `as` type cast on /personal_access_tokens/self response
with Zod schema validation via safeParse(). Returns null with a debug
log if the response shape doesn't match expectations.

Remove manage_context from TOOL_SCOPE_REQUIREMENTS since it manages
local session state and never calls GitLab API — it's always available.

* fix(token-scope): deep-clone scope map, preserve URL subpath, align doc counts

- getToolScopeRequirements() now returns deep clone (arrays copied too)
- getTokenCreationUrl() preserves subpath for self-hosted instances
- Documentation updated: 43 scope-gated tools, read_user=2, read_api=23
- Example log output fixed to show URL-encoded comma (%2C)

* fix(token-scope): validate scopes via z.enum, remove unreliable token type heuristic

- Replace unsafe `as GitLabScope[]` cast with z.enum validation that
  filters unknown scopes (future GitLab scopes are silently ignored)
- Derive GitLabScope type from const array via z.infer
- Remove token type detection by name prefix — token names are
  user-controlled and cannot reliably determine token type

* fix(token-scope): clarify log wording, use unknown token type, add scope filter test

- Log message now says "scope-gated tools" to clarify count excludes
  always-available tools like manage_context
- tokenType defaults to "unknown" since type cannot be reliably inferred
- Add RegistryManager unit test verifying scope-based tool filtering

* fix(test): update tokenType assertion to match unknown default

* fix(token-scope): handle schemeless URL, fix expiry-today logic, update docs

- getTokenCreationUrl() now catches URL parse errors for schemeless
  baseUrl and falls back to string concatenation
- daysUntilExpiry === 0 now logs "expires today" instead of "has expired"
- Troubleshooting docs updated to match current log format

* Update src/services/ConnectionManager.ts

Co-authored-by: Copilot <[email protected]>

* Update src/services/TokenScopeDetector.ts

Co-authored-by: Copilot <[email protected]>

* fix(test): update schemeless URL assertion for URLSearchParams encoding

---------

Co-authored-by: semantic-release-bot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: Use PRIVATE-TOKEN header for PAT authentication instead of Bearer

2 participants