Create a role scoped with bound_claims, e.g. `vault write auth/jwt/role/<ROLE_NAME> role_type="jwt" user_claim="actor" bound_claims='{"repository": "<ORG>/<REPO>", "ref": "refs/heads/main"}' policies="<POLICY_NAME>" ttl="10m"`.
In the workflow YAML, add `permissions: id-token: write` (plus `contents: read`) so the job can request an OIDC token from GitHub.
Exchange the token for Vault credentials with `hashicorp/vault-action` (pinned to a commit SHA) using `method: jwt`, `url: <VAULT_URL>`, `role: <ROLE_NAME>`, `secrets: <SECRET_PATH>` — or manually via `curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=<AUD>"` followed by `vault write auth/jwt/login role=<ROLE_NAME> jwt=<TOKEN>`.
Known gotchas
bound_claims must include at least one condition (e.g. repository); a role with no bound_claims/bound_subject trusts any valid token from GitHub's OIDC issuer, across any repo.
Since Vault 1.17, if the JWT contains an aud claim, the role's bound_audiences must exactly match one of the token's aud claims — a role with a stale or missing bound_audiences can reject otherwise-valid GitHub tokens.
The GitHub ref claim is a full ref path like "refs/heads/main", not just "main" — bound_claims does exact string matching by default (glob matching requires bound_claims_type=glob), so a bare branch name silently never matches.
Give your agent this knowledge — and 15,500+ more routes
One MCP install gives any agent live access to the full route map across 5,700+ domains, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp
Need this verified for your stack — or a route we don't have yet?