Exchange a workflow's GitHub OIDC token for a short-lived limited-permission GitHub App token.
The caller must grant id-token: write. The action does not require stored
credentials: the STS verifies the signed GitHub OIDC token and authorizes it
against the trust policy in the target repository.
The action sends token exchanges with POST /sts/exchange; legacy action
versions that use GET remain compatible during the coordinated rollout.
| Name | Description | Required | Default |
|---|---|---|---|
scope |
Repository (org/repo) or organization whose trust policy to use |
No | Current repository |
policy |
Trust policy name (fetches file in .github/sts/<policy>.sts.yaml within scope repo) |
Yes | |
ttl |
Requested maximum lifetime (30s, 5m, or 1h) |
No | Service/policy maximum |
host |
GitHub STS hostname, without a scheme, port, or path | No | gh-sts.tempoxyz.net |
retry-timeout |
Total OIDC/exchange request and retry budget in seconds (1–3600) | No | 90 |
| Name | Description |
|---|---|
token |
Short-lived GitHub App installation token |
expires-at |
Token expiration timestamp |
permissions:
contents: read
id-token: write
steps:
- name: Fetch GitHub token via STS
id: sts
uses: tempoxyz/gh-actions/actions/github-sts@d39baa2b43f5eba5d261c047521a4fbd56101129 # 2026-09-23T04-31-11Z-d39baa2b
with:
policy: deploy # Uses .github/sts/deploy.sts.yaml as the permissions policy
ttl: 15m
- name: Use the token
env:
GH_TOKEN: ${{ steps.sts.outputs.token }}
run: gh api "repos/${GITHUB_REPOSITORY}"ttl is parsed and enforced by the STS. It must be a positive integer followed
by s, m, or h, resolve to no more than one hour, and cannot exceed the
policy's optional max_ttl. The effective lifetime is the shortest of the
requested TTL, the policy maximum, and GitHub's one-hour installation-token
limit. The expires-at output reports that effective deadline.
The action delegates caller authorization to the STS, which verifies the signed GitHub OIDC token, checks its immutable numeric repository owner ID against the server's allowlist, and enforces the target repository's trust policy. Rejected exchanges fail the action. There is no action-side organization list to update when onboarding an organization; callers already using this version need no action repin for subsequent server-side authorization changes.
The minted installation token is revoked through STS when the job finishes,
so its provider credential and STS ownership-ledger row are cleared together,
including after a failed or cancelled job. Direct GitHub revocation remains a
fail-safe if STS cleanup is unavailable. If the STS exchange is rejected,
the action prints the HTTP status and the server's safe error message (for
example, trust policy: subject did not match) to make policy and
configuration problems easier to diagnose.
OIDC requests, STS worker exchanges, and token revocations retry transient
network errors and HTTP 408, 425, 429, or 5xx responses up to five
times after the initial attempt, with exponential backoff (1, 2, 4, 8, and
16 seconds). Other failures are returned immediately.
OIDC and exchange retries honor Retry-After (seconds or HTTP date) and
x-ratelimit-reset when x-ratelimit-remaining is zero. These delays are minimums:
the action never shortens them to fit its budget. A 429 without a usable
deadline waits at least 60 seconds. If the next retry would exceed
retry-timeout, the action fails with the next permitted retry time instead of
retrying early. Individual requests remain bounded to at most 10 seconds.
After a confirmed 429, the action requests a fresh OIDC assertion after the
wait. Network errors and 5xx retries reuse the original assertion, preserving
STS replay protection when a token may already have been minted. This does not
change post-job revocation retries. Deploy the STS Retry-After response support
before repinning callers; older STS versions use the 60-second 429 fallback.