Skip to content

[Feature]: Provide a way to refresh authentication #37

Closed

Description

@petemounce

Is your feature request related to a problem?

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

Activity

  1. dialupdisaster commented on Apr 30, 2026

    @dialupdisaster
    Contributor

    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.

  2. petemounce commented on Apr 30, 2026

    @petemounce
    Author

    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.

  3. petemounce commented on Apr 30, 2026

    @petemounce
    Author

    (also, and this should have been in my original comment; thank you for writing and maintaining this plugin, I really appreciate it!)

  4. petemounce commented on May 6, 2026

    @petemounce
    Author

    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.
  5. dialupdisaster commented on May 6, 2026

    @dialupdisaster
    Contributor

    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?

  6. dialupdisaster commented on May 6, 2026

    @dialupdisaster
    Contributor

    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.

  7. petemounce commented on May 9, 2026

    @petemounce
    Author

    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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions