Skip to content

Support Gateway-authenticated token grants with client-selected header formats #5473

Open

Description

@freeqaz-openai

User Story

We use OpenShell sandboxes to run stock Git. We need Git to authenticate its first HTTPS fetch with a short-lived token that OpenShell obtains on demand. We want the same provider workflow for API clients that send a credential in a named header.

Problem Statement

Dynamic token_grant profiles support automatic Bearer and raw-header injection. Git uses a Basic header with a username and password, a format OpenShell already supports for static placeholders. Deployments that trust the OpenShell Gateway also need a way to authenticate grant requests without a separate SPIFFE Workload API.

Impact / Why This Matters

To use the existing Basic placeholder path, operators have to provision a credential before the first request. That adds a credential distribution step even when the issuer can mint a scoped token on demand. Configuring automatic injection also puts the choice of header format in the provider profile, where it may differ from what a client already sends.

Proposed Design

Let an operator opt a client_credentials grant into Gateway-signed OAuth client assertions. They configure Gateway JWT signing and supervisor-to-Gateway TLS, create a grant-only provider with --runtime-credentials, and register its immutable provider ID, credential key, and exact HTTPS token endpoint. They then attach the provider to the sandbox. The token service verifies the assertion and authorizes the sandbox, provider credential, and requested resource access. Existing SPIFFE profiles keep their default behavior.

For client-selected formatting, the profile declares one environment variable and one request header on a scoped, inspected HTTPS route. The environment variable holds an opaque handle at startup. Git can send it as a Basic password in Authorization, and an API client can send it as the value of a named header. OpenShell checks the request head and any buffered body bytes before redeeming the grant and substituting the token. The existing body guard checks later bytes as they arrive.

An API provider could declare this credential.

name: api_token
env_vars: [API_TOKEN]
auth_style: placeholder
header_name: X-Api-Key
token_grant:
  grant_type: client_credentials
  assertion_source: openshell_gateway
  token_endpoint: https://issuer.example.com/token

The corresponding Gateway registration would use the same token endpoint.

[[openshell.gateway.provider_assertions]]
provider_id = "<immutable provider ID>"
credential_key = "api_token"
token_endpoint = "https://issuer.example.com/token"

Acceptance Criteria

  • Starting a workload with this credential exposes only the opaque handle and makes no token request.
  • The issuer verifies the Gateway's assertion for the attached sandbox, registered provider credential, and exact token endpoint.
  • Stock Git fetches a fresh object with a Basic header, and a separate API client uses a named header. Both send the handle in the configured header and the authorized upstream receives the issued token.
  • Sending the handle outside the configured route or in a different header cannot redeem the grant.
  • Once OpenShell has applied provider detachment, a Git fetch with the original handle cannot retrieve a new object and causes no additional token endpoint or origin HTTP requests.

Alternatives Considered

The existing SPIFFE assertion remains appropriate for installations that already run a Workload API. Static placeholders support the same header formats and require the material before use. Middleware could format the header for one application. The provider can reuse its existing placeholder handling across clients and keep the handle scoped to the configured route and header.

This proposal uses the existing OAuth token grant contract. The earlier external-broker proposal covered a generic broker reference and withdrawal contract. #4151.

Prototype

The two prototype commits passed three local wire tests for the Gateway assertion exchange, stock Git Basic authentication, and a named API header when applied together to upstream bfa68b20. The tests use local HTTPS origins and a test issuer. Gateway client assertions, grant-backed request headers.

Checklist

  • Reviewed existing issues and the published docs.
  • Submitted as a design proposal with observable acceptance criteria.

Activity

  1. grs commented on Nov 11, 2026

    @grs
    Contributor

    I think it would be better to use grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer for a gateway signed JWT representing the sandbox (see https://www.rfc-editor.org/rfc/rfc7523.html#section-2.1). The assumption for client_credentials is that any assertion supplied identifies a client.

    The issuer for the gateway signed JWT used as the assertion should be an issuer url that can be then used to obtain JWKS keys for verification in a standard way.

    This would make the approach more likely to be usable in different contexts, and aligns well with WAG (https://www.ietf.org/archive/id/draft-carleton-workload-authz-grant-01.html)

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

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions