Workflow Usage
Each pattern below assumes the prerequisites from the Quickstart: a reachable server, an installed GitHub App, and a trust policy in the target repository.
Access another repository
This is the case the action exists for. The workflow runs in one repository and needs write access to another, without a personal access token.
The trust policy lives in the target repository and names the source workflow. The scope input names the target.
jobs:
sync:
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: Depthmark/github-sts-action@v0.2.0
id: sts
with:
sts-url: ${{ vars.STS_URL }}
audience: https://sts.example.com
scope: other-org/private-repo
identity: sync-bot
- name: Clone the target
env:
GH_TOKEN: ${{ steps.sts.outputs.token }}
run: gh repo clone other-org/private-repoOrganization-level scope is not supported by the current server release. To reach several repositories, run one exchange per target repository.
Select a GitHub App
When the server has more than one app configured, name the one to use. The app input also selects the policy directory, so app: deploy-bot with identity: deploy loads .github/sts/deploy-bot/deploy.sts.yaml.
- uses: Depthmark/github-sts-action@v0.2.0
id: sts
with:
sts-url: ${{ vars.STS_URL }}
audience: https://sts.example.com
scope: my-org/my-repo
identity: deploy
app: deploy-botOmit app when the server has a single app. A name that the server does not know fails with app_unknown.
Set the audience explicitly
The audience input defaults to github-sts. Set it explicitly so the workflow states the value it depends on, and so a change to the trust policy’s audience: field produces an obvious diff on both sides.
- uses: Depthmark/github-sts-action@v0.2.0
id: sts
with:
sts-url: ${{ vars.STS_URL }}
audience: https://sts.example.com
scope: my-org/my-repo
identity: ciA mismatch between this value and the policy fails with audience_mismatch, never with a partially granted token.
Centralize the server URL
Store the server URL in a GitHub Actions variable at the organization or repository level rather than repeating it in every workflow. Moving the server later then touches one setting instead of every workflow file.
with:
sts-url: ${{ vars.STS_URL }}The URL is not a secret. It appears in the log on connection failures, which is intentional and makes those failures diagnosable.
Keep the token inside the steps that need it
Pass the token through a step-level env block. A job-level env block would expose it to every step in the job, including third-party actions.
# Scoped to this step only
- name: Push changes
env:
GH_TOKEN: ${{ steps.sts.outputs.token }}
run: gh pr create --fillGrant the OIDC permission per job
Declare id-token: write on the job that performs the exchange. A workflow-level declaration gives every job the ability to request OIDC tokens, including jobs that only run linters.
permissions: {}
jobs:
deploy:
permissions:
id-token: write
contents: read
steps:
- uses: Depthmark/github-sts-action@v0.2.0
# ...
lint:
permissions:
contents: read
steps:
# This job cannot request an OIDC token.Use one identity per purpose
Create a separate trust policy per workflow rather than one broad policy shared by several. Separate policies can be revoked and audited independently, and each one grants only the permissions its workflow needs.
.github/sts/default/
ci.sts.yaml read-only
deploy.sts.yaml write, main branch only
release.sts.yaml write, release workflow onlySee Policy Recipes for the policy side of this split.
Handle a failed exchange
By default a failed exchange fails the step and stops the job, which is usually what you want. When the workflow needs to react to the reason instead, set continue-on-error: true and read error-code.
- uses: Depthmark/github-sts-action@v0.2.0
id: sts
continue-on-error: true
with:
sts-url: ${{ vars.STS_URL }}
audience: https://sts.example.com
scope: my-org/my-repo
identity: ci
- name: Fall back to read-only mode
if: steps.sts.outcome == 'failure'
run: echo "Continuing without elevated access: ${{ steps.sts.outputs.error-code }}"The full list of values, and which ones are worth retrying, is in the Error Reference.
A worked example: this action’s own release workflow
The action’s release workflow uses the action to authenticate itself. It exchanges its OIDC token for a depthmark-release-bot installation token, then pushes the moved major version tag with that token.
permissions:
contents: write
id-token: write
steps:
- name: Exchange OIDC token for a release-bot token
id: sts
uses: Depthmark/github-sts-action@v0.2.0
with:
sts-url: https://sts.example.com
scope: my-org/my-repo
identity: release
app: depthmark-release-bot
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
token: ${{ steps.sts.outputs.token }}The matching policy accepts tokens minted only for that one workflow file on the default branch, and binds the source and target repositories by their immutable numeric IDs. No personal access token exists in the repository. The published policy is release.sts.yaml.