denoland/deno · error
Failed to get OIDC token: status {}, response: '{}'
Error message
Failed to get OIDC token: status {}, response: '{}' What it means
When publishing tokenless from GitHub Actions via OIDC, Deno mints a JSR-audience token by calling the Actions OIDC endpoint (`ACTIONS_ID_TOKEN_REQUEST_URL`) with the job's bearer token. Any non-2xx reply produces this error with the HTTP status and the response body. Typical bodies are 'token expired' (OIDC tokens are short-lived) or permission/audience errors from GitHub.
Source
Thrown at cli/tools/publish/mod.rs:782
);
let response = client
.get(url.parse()?)?
.header(
http::header::AUTHORIZATION,
format!("Bearer {}", oidc_config.token).parse()?,
)
.send()
.await
.context("Failed to get OIDC token")?;
let status = response.status();
let text = crate::http_util::body_to_string(response)
.await
.with_context(|| {
format!("Failed to get OIDC token: status {}", status)
})?;
if !status.is_success() {
bail!(
"Failed to get OIDC token: status {}, response: '{}'",
status,
text
);
}
let registry::OidcTokenResponse { value } = serde_json::from_str(&text)
.with_context(|| {
format!(
"Failed to parse OIDC token: '{}' (status {})",
text, status
)
})?;
let authorization: Rc<str> = format!("githuboidc {}", value).into();
for pkg in chunked_packages.next().unwrap() {
authorizations.insert(
(pkg.scope.clone(), pkg.package.clone(), pkg.version.clone()),
authorization.clone(),View on GitHub (pinned to f7822238ca)
Solutions
- Re-run the job — an expired/short-lived OIDC token is the most common cause and a retry mints a fresh one.
- Add `permissions: id-token: write` (and `contents: read`) to the publishing job or workflow.
- If it persists, publish with an explicit token: `deno publish --token <JSR_TOKEN>`.
Example fix
# .github/workflows/publish.yml (before)
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: deno publish
# after
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- run: deno publish Defensive patterns
Strategy: retry
Validate before calling
#!/usr/bin/env bash
# verify the OIDC prerequisites before publishing
[ "${GITHUB_ACTIONS:-}" = "true" ] || { echo "not in GitHub Actions — use --token or skip" >&2; exit 1; }
[ -n "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ] || { echo "job needs permissions: id-token: write" >&2; exit 1; } Try / catch
#!/usr/bin/env bash
for attempt in 1 2 3; do
out="$(deno publish 2>&1)" && exit 0
if printf '%s' "$out" | grep -q 'Failed to get OIDC token'; then
echo "OIDC mint failed (attempt $attempt) — backing off" >&2
sleep $((attempt * 30)) # a retry mints a fresh, unexpired token
continue
fi
printf '%s\n' "$out" >&2; exit 1
done
exit 1 Prevention
- Declare `permissions: id-token: write, contents: read` on the publishing job.
- Keep publish jobs short — OIDC tokens expire, and long multi-package runs are the main trigger.
- Fall back to `--token <JSR_TOKEN>` (stored as a secret) when retries keep failing.
When it happens
Trigger: Auth method resolved to OIDC (`GITHUB_ACTIONS=true`, `ACTIONS_ID_TOKEN_REQUEST_URL`/`ACTIONS_ID_TOKEN_REQUEST_TOKEN` present, no `--token`) and the token endpoint answered with status >= 400 — e.g. 403 expired token on long-running multi-chunk publishes, 401 when the job lacks id-token permission.
Common situations: Slow CI publish jobs whose minted token expires; workflows missing `permissions: id-token: write`; transient GitHub OIDC service errors; large workspaces published in 16-package chunks.
Related errors
- Automatic provenance is only available in GitHub Actions
- Provenance generation in Github Actions requires 'id-token'
- Not running in GitHub Actions
- No means to authenticate. Pass a token to `--token`, or enab
- GITHUB_REPOSITORY environment variable is not set
AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20).
Data as JSON: /api/errors/675a063a3c73508e.
Report an issue: GitHub.