Skip to content

fix(api): accept service account keys on the Bearer auth path - #263

Closed
wangzhengzhuo05 wants to merge 3 commits into
marmotdata:mainfrom
wangzhengzhuo05:fix/service-account-key-bearer
Closed

wangzhengzhuo05 wants to merge 3 commits into
marmotdata:mainfrom
wangzhengzhuo05:fix/service-account-key-bearer

Conversation

@wangzhengzhuo05

Copy link
Copy Markdown

What

A valid service-account key sent as Authorization: Bearer <key> got a 401 Invalid token. The X-API-Key path accepted the same key, so the two carriers disagreed.

Why

WithAuth has two API-key carriers. X-API-Key validated the user key and then fell back to globalServiceAccountService.ValidateAPIKey, but the Authorization: Bearer fallback called only userService.ValidateAPIKey. A service-account key is not a user key, so user.ErrInvalidAPIKey propagated straight to the 401.

How

  • Extracted the duplicated service-account validation into one unexported helper, serviceAccountPrincipal(ctx, apiKey), which returns the matching auth.Principal and an ok flag. It preserves the existing role/permission projection and the globalServiceAccountService == nil guard.
  • The X-API-Key path now calls that helper (behaviour unchanged — same guard, same order, same 401).
  • The bearer fallback now mirrors the X-API-Key path: user key first, then service-account key, then the refusal. The K8s ServiceAccount-token branch, OIDC exchange, anonymous branch, JWT and user-key behaviour are untouched.

Tests

New internal/api/v1/common/middleware_serviceaccount_test.go, using the existing mockUserService/mockAuthService from middleware_oidc_test.go plus a mockServiceAccountService. Four subtests:

  • service-account key on the bearer path → 200, principal type service_account (401 before this change)
  • same request with no registered service-account service → 401 (the refusal is preserved)
  • unknown service-account key → 401
  • valid user key on the bearer path → 200, principal type user (the user path is not displaced)
gofmt -l internal/api/v1/common/          # only middleware_oidc_test.go, which is unformatted on main and untouched here
go build ./...                            # ok
go test ./internal/api/v1/common/... -count=1
ok  github.com/marmotdata/marmot/internal/api/v1/common  0.017s
go test ./internal/core/user/... ./internal/core/serviceaccount/... ./internal/api/... -count=1   # all ok

Mutation check

Disabling the new bearer fallback (if errors.Is(err, user.ErrInvalidAPIKey)if false) makes the new test fail with expected 200, got 401 while the other three subtests still pass — so the test guards this fix and not the surrounding behaviour. Restoring the helper returns the package to green.

Fixes #253

The Authorization: Bearer fallback in WithAuth only validated user API
keys, so a service account key that works in X-API-Key got a 401 as a
bearer token. Extract the service-account validation into a shared
helper and fall through to it on the bearer path too.

Fixes marmotdata#253
@github-actions github-actions Bot added the area/server Server, CLI and shared packages label Sep 13, 2026
@bschaatsbergen

Copy link
Copy Markdown
Member

/assign

@wangzhengzhuo05

Copy link
Copy Markdown
Author

Closing this out \u2014 I'm wrapping up my open-source contribution activity and don't want to leave work sitting in maintainers' queues indefinitely.\n\nThe change itself is still valid and CI is green: feel free to cherry-pick the patch, take just the test, or adapt it in whatever direction fits this codebase best. I'm happy to reopen if you'd rather review it as-is, and I can answer questions on the approach for as long as the branch stays around.\n\nThanks for taking the time to look at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/server Server, CLI and shared packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Service account keys are rejected in Authorization: Bearer

2 participants