Ephemeral credentials for agents: what changes with GitHub Apps

GitHub's new stateless format exposes brittle assumptions about length, storage, and redaction. This guide turns the change into an operable credential contract for coding agents.

Ephemeral credentialsGitHub AppsCoding agentsLeast privilege
Wasyra Engineering
Modernization, architecture, and reliable delivery
Published
min read
8 min read
Categoría
Engineering
5gates for agent credentials
Coding agent receiving an ephemeral credential through a gateway and accessing only one repository while other paths remain blocked.

Chapter 01

A format change can reveal a missing boundary

A coding agent may need to read files, open branches, comment on pull requests, or update checks. The tempting design is to hand it a broad credential when the worker starts and recover it when the job ends. That design works only while the token fits every column, passes through every proxy, stays hidden in every log, and never outlives the task. One false assumption is enough to turn useful automation into a lateral path toward repositories the job never needed to touch.

On October 2, 2026, three Lima calendar days before this article, GitHub announced completion of the rollout that began on April 27: new GitHub App installation tokens are now issued by default in the stateless ghs_APPID_JWT format. According to the announcement, they are now roughly 520 characters rather than 40 and are intended to make issuance and validation faster while improving API reliability. Repository scope, permissions, endpoint, and one-hour expiration did not change. The central news is completion of the rollout, not the arrival of a new least-privilege capability.

Chapter 02

The mechanism: stable identity, short-lived capability

A GitHub App represents an application identity installed by an organization or account. The service signs a JWT as the app, identifies the installation, and requests an access token. That request can narrow repositories and permissions without exceeding what the installation was granted. The response includes the token, its expiration, and its effective scope; the token expires one hour after creation. An SDK such as Octokit can regenerate it after expiration.

Stateless describes how GitHub issues and validates the credential; it does not authorize local decoding as a basis for policy decisions. The explicit guidance is to treat it as an opaque string. Nor does the format make an agent safe by itself: a one-hour credential with write access to one hundred repositories is still too powerful for a read task in one. A sound architecture separates installation identity, job intent, and temporary capability. The agent receives only the third and never the private key that could mint new capabilities.

Chapter 03

1. Isolate the issuer from the agent runtime

Keep the GitHub App private key in a credential broker, not in the agent image, its prompt, a shared runner, or an environment variable available to every tool. The broker authenticates the internal request, resolves tenant, installation, and job, and decides whether issuance is allowed. It then returns an already-scoped installation token. If malicious instructions inside an issue compromise the agent, it finds only the current job capability; it does not obtain the material needed to mint another with broader access.

The broker contract should accept a verifiable workload identity and structured intent, such as repository, pull request, operation, and expected duration. It should not accept a free-form field saying full access needed. Bind every issuance to job_id, installation, repositories, permissions, approving actor, and policy hash. That trace does not store the token; it stores why the token existed. If a platform runs agents for multiple customers, this separation also prevents one tenant's cache or process from reusing another tenant's installation.

Chapter 04

2. Derive scope from the plan, not the installation maximum

The installation defines a ceiling; each task should request less. An agent that summarizes a pull request needs metadata and contents for one repository, probably read-only. One that publishes a check may need checks write access, but not administration, secrets, or every repository in the organization. GitHub allows repository_ids and permissions when creating the token. If those fields are omitted, the credential inherits everything granted to the installation, which may be much broader than the job's intent.

Turn every tool into a declared operation and map that operation to permissions, not vague roles such as agent-editor. Reject plans whose sequence requires an unapproved capability, and request explicit elevation only for the step that needs it. A 403 response is a policy or scope signal, not an automatic reason to reissue with full permissions. Also measure which issued permissions were actually used: the gap between granted and used shows where the next policy can be tightened.

Chapter 05

3. Test the credential as opaque data end to end

The jump from roughly 40 to 520 characters is a free test of hidden assumptions. Trace the broker, queue, serializer, database, secret store, sidecar, proxy, gateway, and HTTP client. Remove exact-length checks and parsers that infer privilege from dots, prefixes, or segments. Expanding one column is not enough if middleware truncates the Authorization header or a schema validator rejects the value before it reaches GitHub.

GitHub will retire the temporary X-GitHub-Stateless-S2S-Token header on November 30, 2026; it allowed teams to force formats during the transition. Before removing it, run a matrix covering both formats across issuance, consumption, 401 handling, renewal, and redaction. Then remove it from production code: keeping a migration flag as a permanent dependency creates a path the provider has already said it will stop honoring.

Chapter 06

4. Reduce distribution and fix redaction before increasing autonomy

An ephemeral credential remains a secret while it is alive. Deliver it to the exact process making the call and, where practical, keep the model separate from the executor that constructs Authorization. Do not include it in tool messages, events, spans, error dumps, command-line arguments, or evaluation artifacts. If the agent needs several APIs, use independent credentials per provider; one shared environment chain turns compromise of one tool into exposure of all of them.

Update redaction for long values and future variants without relying only on the historical 40-character regex. The primary defense is not logging sensitive headers; pattern detection is a second barrier. Test application, proxy, and observability logs with synthetic values containing dots, hyphens, and underscores, and verify that neither the full token nor useful fragments appear. Keep non-secret issuance identifiers so incidents can be correlated without copying credentials.

Chapter 07

5. Design renewal, revocation, and retry as states

One hour is an upper bound, not the job's promised duration. The token can expire during a long run, be revoked, or become invalid after an installation change. Model valid, near-expiry, expired, and revoked states. Renew through the broker under the same policy and revalidate current intent: a job that moved repositories or changed from read to write should not automatically recycle its initial approval.

On a 401, avoid a storm in which every tool mints its own token and repeats a mutation. Centralize renewal, use per-job exclusion, and retry only idempotent operations or those protected by an idempotency key. To stop an incident, revoke the token and suspend new issuance for the installation, tenant, or policy; then invalidate pending workers. Recovery is complete when no new tokens are issued, active capabilities have expired or been revoked, and the audit trail explains which operations reached GitHub.

Chapter 08

Hypothetical example and pre-release evaluation

Hypothetical example: an agent receives an issue asking it to update a dependency in payments-repo. The orchestrator builds a plan covering contents read, branch creation, contents write, and opening a pull request. The broker verifies that the issue belongs to the tenant, issues a token limited to payments-repo with the corresponding permissions, and records the decision. An embedded instruction tries to read payroll-repo: the tool blocks it because that repository is out of scope, without requesting automatic elevation. After the pull request is complete, the token is discarded and the job retains only non-secret evidence.

Evaluate five suites: scope, transport, secrecy, lifecycle, and recovery. Inject unauthorized repositories and missing permissions; send long synthetic tokens through the entire path; trigger logs and errors; advance the clock and simulate revocation; cut the network after a mutation. Success is not merely that the happy path publishes a pull request. You must prove that an out-of-contract action never reaches GitHub, no log reveals the credential, renewal preserves or narrows scope, and retries do not duplicate effects.

Chapter 09

The decision: authorize jobs, not abstract agents

Stateless tokens do not remove the need for secure storage, automatically reduce permissions, or protect against a tool correctly using an overbroad credential. They also do not replace human review for high-impact changes or controls over commands, networks, and artifacts. Their editorial value is that they expose debt that already existed: if 480 additional characters break the integration, the system probably also carried brittle assumptions about who may mint, transport, and observe the secret.

Approve the integration when the five gates leave evidence: an isolated issuer, plan-derived scope, opaque transport, minimal distribution, and rehearsed recovery. The unit of authorization should not be the generic agent, but an identified job with a purpose and a boundary. If you need to turn this boundary into an agent pilot with tools, permissions, traces, and evaluations, Wasyra's custom agent service can help design it. It is an implementation service separate from the product available at agents.wasyra.com.

FAQ

Frequently asked questions

Does the stateless format make a coding agent safer?

Not by itself. GitHub keeps permissions, scope, and expiration unchanged. Safety depends on isolating the issuer, narrowing each task token, preventing leaks, and controlling renewal and revocation.

Should I decode the JWT to decide what the agent may do?

No. Treat the installation token as an opaque string and keep the policy decision in your broker. GitHub validates the credential when it receives the request.

What should I test before November 30, 2026?

Test both formats end to end, fix length, transport, and redaction, and remove the temporary X-GitHub-Stateless-S2S-Token header from production code after validation.

Written by

Wasyra Engineering

Modernization, architecture, and reliable delivery

Wasyra Engineering documents patterns for moving legacy systems without freezing delivery or breaking ownership.

LegacyRefactorArchitecture
More from this author

Series

AI systems that actually reach production

A series on agents, copilots, and guardrails for bringing AI into real work without breaking trust or operations.

Posts in this series

Keep reading

Keep reading