You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Feature]: Provide a way to refresh authentication #37
I send OpenTelemetry signals to a collector hosted as a GCP Cloud Run service. This has an authentication timeout of 60min.
At the moment there is no (obvious to me, maybe I missed it) mechanism to acquire/refresh authentication, which means after 60min I'll have data loss.
Describe the solution you'd like
I'd like to be able to set up a script/binary so that it can be called when requests are rejected with 401/403/whatever, and it runs to refresh authentication.
Prior art: Claude has support for this via "dynamic headers".
My script (for claude) basically checks Google Application Default Credentials are set and not expiring soon (and if not, calls gcloud auth login --update-adc), then shoves gcloud auth print-access-token into {"Authorization": "Bearer {here}"} (JSON as claude's integration allows a set of headers to be returned).
Describe alternatives you've considered
Perhaps the plugin itself might implement authentication - but probably not as that would then increase the scope to every potential backend's authentication options.
Perhaps a hook that fires pre-prompt - but now I see that an opencode plugin is a set of hooks already. Plus, that might not actually be often enough depending on the time any given prompt needs to get an answer back.
Telemetry type
Configuration, Metrics
Additional context
No response
Checklist
I have searched existing issues and discussions for similar feature requests
I have checked the changelog to see if this already exists
This does seem in scope for the plugin. The plugin owns OTLP exporter configuration, and static startup-only headers are not sufficient for collectors that require short-lived auth.
I’d propose keeping this backend-agnostic rather than implementing GCP-specific auth:
Add an OPENCODE_OTLP_HEADERS_HELPER setting pointing at an executable script/binary.
The helper writes a JSON object to stdout, for example { "Authorization": "Bearer ..." }.
Static OPENCODE_OTLP_HEADERS continues to work, and helper-provided headers override static headers with the same name.
Exporters try to send with the current headers first.
If an export fails with an auth-like error (401/403 for HTTP, UNAUTHENTICATED/PERMISSION_DENIED for gRPC), the plugin runs the helper, refreshes the exporter headers, and retries that export once.
Use a single in-flight refresh promise so metrics/logs/traces failing at the same time do not launch multiple helper processes.
If the retry still fails, let the export fail normally and log the refresh/export error without logging header values.
I prefer this over a timer/debounce because it avoids unnecessary helper execution, handles unpredictable expiry, and lets the failed batch get one chance to be sent after refresh.
Is there any complexity to resolve regarding credential acquisition crossing over the exporter export intervals? As in, there are 2 exporters (3 if traces become supported) both independently making requests on independent cadences. They share the credential acquisition machinery; it will need to be gated.
Re: refreshing credentials - the approach you have a preference for trades off lower frequency/cost of auth calls vs higher risk of data-loss (with short warning window) in the event of credentials failure. I would hazard that most clients will not prominently display failed observability publishing to users, and I would further hazard that most users will not be subject matter experts to debug, and further are unlikely to care about this data-loss as it's not their data-loss; it's orthogonal to whatever they might be working on.
That makes me think the chance of recovery is slim too none in the event of failure to auth. Would it be reasonable to use a periodic refresh (scheduled for every half-expiry), and publish auth_expiry and auth_duration metrics to allow centralised detection of authentication problems? My thought is that "normal" looks like auth_expiry > (auth_duration/2 - some_jitter) for any given client. An alert might be defined for telemetry going silent, and an investigation can conclude auth if they see auth_expiry dropping below half auth_duration before the silence.
Just checking back in on this - it works with a couple of caveats:
I'd failed to appreciate opencode.json will cache plugins and I hadn't pinned. 🤦
The path to the helper needs to be an absolute path to not break if opencode is invoked inside a sub-directory (unless there's a way to supply the repository root via some config interpolation I don't know about?)
The otel collector logs contain the expected 403s of first-request auth-failure. It'd be nice from an operator UX point of view to execute the helper on opencode startup or first-prompt if the helper's env-var is set to reduce that to 0.
Following up on the earlier concurrency / proactive-refresh question.
The current implementation already coalesces concurrent auth refreshes behind a single in-flight promise, so if metrics/logs/traces all hit an auth failure around the same time they should share one helper execution rather than stampeding.
What we have not implemented is the more proactive model you described: periodic refresh before expiry plus auth health/expiry metrics. I think that would take a meaningfully larger change than the current helper design:
the helper contract would likely need to expand beyond "return headers JSON" to also return expiry / TTL metadata
we would need a scheduler with refresh timing, jitter, startup behavior, and failure/backoff handling
we would need to define what auth-health metrics should look like across helper implementations and transports
we would also need extra tests/docs around lifecycle, failure modes, and how those metrics should be interpreted operationally
The benefit would be better operator UX and potentially earlier detection of auth drift before telemetry goes silent. The tradeoff is quite a bit more complexity in both implementation and the configuration contract.
For now I’ve taken the smaller step of prewarming the helper at startup so the first export can use fresh credentials, while keeping the existing refresh-on-auth-failure path for later expiry.
From your perspective, would the additional proactive-refresh / expiry-metrics model be worth that extra complexity, or does startup prewarm plus on-demand refresh cover most of the operational pain in practice?
Implemented in #46: prewarm the OTLP headers helper at startup, and document absolute helper paths plus ${PROJECT_ROOT} / ${WORKTREE} / ${DIRECTORY} placeholders for project-relative configuration.
Activity
dialupdisaster commentedon Apr 30, 2026
This does seem in scope for the plugin. The plugin owns OTLP exporter configuration, and static startup-only headers are not sufficient for collectors that require short-lived auth.
I’d propose keeping this backend-agnostic rather than implementing GCP-specific auth:
OPENCODE_OTLP_HEADERS_HELPERsetting pointing at an executable script/binary.{ "Authorization": "Bearer ..." }.OPENCODE_OTLP_HEADERScontinues to work, and helper-provided headers override static headers with the same name.401/403for HTTP,UNAUTHENTICATED/PERMISSION_DENIEDfor gRPC), the plugin runs the helper, refreshes the exporter headers, and retries that export once.I prefer this over a timer/debounce because it avoids unnecessary helper execution, handles unpredictable expiry, and lets the failed batch get one chance to be sent after refresh.
petemounce commentedon Apr 30, 2026
Is there any complexity to resolve regarding credential acquisition crossing over the exporter export intervals? As in, there are 2 exporters (3 if traces become supported) both independently making requests on independent cadences. They share the credential acquisition machinery; it will need to be gated.
Re: refreshing credentials - the approach you have a preference for trades off lower frequency/cost of auth calls vs higher risk of data-loss (with short warning window) in the event of credentials failure. I would hazard that most clients will not prominently display failed observability publishing to users, and I would further hazard that most users will not be subject matter experts to debug, and further are unlikely to care about this data-loss as it's not their data-loss; it's orthogonal to whatever they might be working on.
That makes me think the chance of recovery is slim too none in the event of failure to auth. Would it be reasonable to use a periodic refresh (scheduled for every half-expiry), and publish auth_expiry and auth_duration metrics to allow centralised detection of authentication problems? My thought is that "normal" looks like
auth_expiry > (auth_duration/2 - some_jitter)for any given client. An alert might be defined for telemetry going silent, and an investigation can conclude auth if they see auth_expiry dropping below half auth_duration before the silence.petemounce commentedon Apr 30, 2026
(also, and this should have been in my original comment; thank you for writing and maintaining this plugin, I really appreciate it!)
petemounce commentedon May 6, 2026
Just checking back in on this - it works with a couple of caveats:
403s of first-request auth-failure. It'd be nice from an operator UX point of view to execute the helper on opencode startup or first-prompt if the helper's env-var is set to reduce that to 0.dialupdisaster commentedon May 6, 2026
Following up on the earlier concurrency / proactive-refresh question.
The current implementation already coalesces concurrent auth refreshes behind a single in-flight promise, so if metrics/logs/traces all hit an auth failure around the same time they should share one helper execution rather than stampeding.
What we have not implemented is the more proactive model you described: periodic refresh before expiry plus auth health/expiry metrics. I think that would take a meaningfully larger change than the current helper design:
The benefit would be better operator UX and potentially earlier detection of auth drift before telemetry goes silent. The tradeoff is quite a bit more complexity in both implementation and the configuration contract.
For now I’ve taken the smaller step of prewarming the helper at startup so the first export can use fresh credentials, while keeping the existing refresh-on-auth-failure path for later expiry.
From your perspective, would the additional proactive-refresh / expiry-metrics model be worth that extra complexity, or does startup prewarm plus on-demand refresh cover most of the operational pain in practice?
dialupdisaster commentedon May 6, 2026
Implemented in #46: prewarm the OTLP headers helper at startup, and document absolute helper paths plus
${PROJECT_ROOT}/${WORKTREE}/${DIRECTORY}placeholders for project-relative configuration.petemounce commentedon May 9, 2026
Startup pre warm is likely to cover most of the operator UX in practice.
Re: expiry/TTL - I think (in the gcp case anyhow) these are base64 encoded JWTs? If so, expiry ought to be baked into the token itself.