Skip to content

feat(auth): add Grafana Cloud access policy token authentication#563

Draft
sd2k wants to merge 4 commits intomainfrom
fix-561
Draft

feat(auth): add Grafana Cloud access policy token authentication#563
sd2k wants to merge 4 commits intomainfrom
fix-561

Conversation

@sd2k
Copy link
Collaborator

@sd2k sd2k commented Feb 10, 2026

Summary

Adds support for authenticating with Grafana instances using Cloud access policy tokens as an alternative to service account tokens or API keys.

  • mcpgrafana.go: Added GRAFANA_CLOUD_ACCESS_POLICY_TOKEN env var support, CloudAccessPolicyToken config field, extraction from both env and X-Cloud-Access-Policy-Token request header (header takes precedence), and X-Access-Token header injection across all transport paths (BuildTransport, NewGrafanaClient)
  • proxied_client.go: Added X-Access-Token header for proxied MCP datasource connections
  • mcpgrafana_test.go: Tests covering env extraction, header extraction with precedence, and transport header injection (with and without extra headers)
  • README.md: Documentation for the new authentication method including configuration example

Closes #561

Test plan

  • Verify TestCloudAccessPolicyTokenFromEnv passes (token set and unset scenarios)
  • Verify TestCloudAccessPolicyTokenFromHeaders passes (header-only, env-only, and header-takes-precedence scenarios)
  • Verify TestCloudAccessPolicyTokenTransport passes (header injection via BuildTransport, no header when unset, coexistence with extra headers)
  • Verify existing tests continue to pass (no regressions in auth handling)
  • Manual test: configure GRAFANA_CLOUD_ACCESS_POLICY_TOKEN against a Grafana Cloud instance and confirm successful authentication

🤖 Generated with Claude Code


Note

Medium Risk
Touches request authentication/header injection across multiple client transports; mistakes could cause auth failures or unintended credential precedence, though the change is gated and covered by unit tests.

Overview
Adds Grafana Cloud access policy token authentication as an alternative to service account/API key auth.

Introduces GRAFANA_CLOUD_ACCESS_POLICY_TOKEN (and X-Cloud-Access-Policy-Token for SSE/HTTP) to populate a new GrafanaConfig.CloudAccessPolicyToken, and injects the corresponding X-Access-Token: Bearer ... header across client/transport paths (including proxied MCP datasource connections), while explicitly not overriding on-behalf-of auth when AccessToken is set. Includes unit tests for env/header precedence and transport header injection, plus README documentation and examples.

Written by Cursor Bugbot for commit cc1c96a. This will update automatically on new commits. Configure here.

Add support for authenticating with Grafana instances using Cloud access
policy tokens as an alternative to service account tokens or API keys.

The token is read from the GRAFANA_CLOUD_ACCESS_POLICY_TOKEN environment
variable and sent as a Bearer token in the X-Access-Token header. For
SSE/streamable HTTP transports, the token can also be provided via the
X-Cloud-Access-Policy-Token request header, which takes precedence over
the environment variable.

The implementation covers all transport paths: BuildTransport for direct
clients, NewGrafanaClient for reflection-based client setup, and
NewProxiedClient for datasource proxy connections.

Closes #561

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

@sd2k sd2k marked this pull request as ready for review February 10, 2026 12:48
@sd2k sd2k requested a review from a team as a code owner February 10, 2026 12:48
@cursor

This comment has been minimized.

…ctive

Both CloudAccessPolicyToken and on-behalf-of AccessToken use the
X-Access-Token header. When OBO auth is active, the cloud token's
ExtraHeadersRoundTripper would clone the request and overwrite the
header set by authRoundTripper, silently breaking OBO auth.

Skip adding the cloud access policy token header in BuildTransport and
NewGrafanaClient when AccessToken is set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is ON. A Cloud Agent has been kicked off to fix the reported issue.

@cursor
Copy link

cursor bot commented Feb 10, 2026

Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.

  • ✅ Fixed: Missing OBO auth guard in proxied client
    • Added the missing '&& config.AccessToken == ""' guard to the CloudAccessPolicyToken check in proxied_client.go to match the pattern used in BuildTransport and NewGrafanaClient, ensuring OBO authentication takes precedence.

Create PR

Or push these changes by commenting:

@cursor push b7baec6864
Preview (b7baec6864)
diff --git a/proxied_client.go b/proxied_client.go
--- a/proxied_client.go
+++ b/proxied_client.go
@@ -36,8 +36,10 @@
 		headers["Authorization"] = "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
 	}
 
-	// Add cloud access policy token header if configured
-	if config.CloudAccessPolicyToken != "" {
+	// Add cloud access policy token header only when on-behalf-of auth is not
+	// active. OBO auth also uses X-Access-Token (set by authRoundTripper in
+	// tool-specific clients) and should take precedence.
+	if config.CloudAccessPolicyToken != "" && config.AccessToken == "" {
 		headers["X-Access-Token"] = "Bearer " + config.CloudAccessPolicyToken
 	}

Add the missing `config.AccessToken == ""` guard to the
CloudAccessPolicyToken check in proxied_client.go, matching the
pattern already used in BuildTransport and NewGrafanaClient.

Without this guard, the cloud access policy token would overwrite the
OBO token for proxied datasource connections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link

MCP Token Analysis

Passed

Metric Value
Baseline 14373 tokens
Current 14373 tokens
Change +0 (+0.0%)

@sd2k sd2k marked this pull request as draft February 12, 2026 19:14
Instead of sending the Cloud Access Policy token directly as
X-Access-Token, use authlib's TokenExchangeClient to exchange it
for a signed access token via the Auth API's /v1/sign-access-token
endpoint. The TokenExchangeClient provides built-in caching (TTL
from JWT expiry - 15s), singleflight dedup, and retry logic.

New environment variables: GRAFANA_TOKEN_EXCHANGE_URL and
GRAFANA_TOKEN_EXCHANGE_NAMESPACE. Corresponding HTTP headers:
X-Token-Exchange-URL and X-Token-Exchange-Namespace.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to authenticate using Cloud Access policy tokens

1 participant