denoland/deno · error · AnyError
No means to authenticate. Pass a token to `--token`, or enab
Error message
No means to authenticate. Pass a token to `--token`, or enable tokenless publishing from GitHub Actions using OIDC. Learn more at https://deno.co/ghoidc
What it means
Raised by `deno publish` when no authentication method is available: no token was passed via `--token` (or environment), and the process is inside GitHub Actions but the OIDC token endpoint variables (`ACTIONS_ID_TOKEN_REQUEST_URL` / `ACTIONS_ID_TOKEN_REQUEST_TOKEN`) are missing. The check only attempts OIDC when `GITHUB_ACTIONS=true`; if both env lookups fail there, publishing has no way to authenticate to jsr.io.
Source
Thrown at cli/tools/publish/auth.rs:36
}
pub(crate) fn is_gha() -> bool {
std::env::var("GITHUB_ACTIONS").unwrap_or_default() == "true"
}
pub(crate) fn gha_oidc_token() -> Option<String> {
std::env::var("ACTIONS_ID_TOKEN_REQUEST_TOKEN")
.ok()
.filter(|s| !s.is_empty())
}
fn get_gh_oidc_env_vars() -> Option<Result<(String, String), AnyError>> {
if std::env::var("GITHUB_ACTIONS").unwrap_or_default() == "true" {
let url = std::env::var("ACTIONS_ID_TOKEN_REQUEST_URL");
let token = std::env::var("ACTIONS_ID_TOKEN_REQUEST_TOKEN");
match (url, token) {
(Ok(url), Ok(token)) => Some(Ok((url, token))),
(Err(_), Err(_)) => Some(Err(anyhow::anyhow!(
"No means to authenticate. Pass a token to `--token`, or enable tokenless publishing from GitHub Actions using OIDC. Learn more at https://deno.co/ghoidc"
))),
_ => None,
}
} else {
None
}
}
pub fn get_auth_method(
maybe_token: Option<String>,
dry_run: bool,
) -> Result<AuthMethod, AnyError> {
if dry_run {
// We don't authenticate in dry-run mode.
return Ok(AuthMethod::Interactive);
}
View on GitHub (pinned to 9ad36f7a2c)
Solutions
- In GitHub Actions add `permissions: id-token: write` to the publish job so the OIDC env vars are injected, enabling tokenless publishing.
- Otherwise create a JSR access token (jsr.io -> account settings) and pass it: `deno publish --token <token>` (or inject via a masked secret in CI: `deno publish --token ${{ secrets.JSR_TOKEN }}`).
- Verify the environment actually exposes both ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN when GITHUB_ACTIONS=true; if your wrapper strips env, export them through.
Example fix
# before (job without OIDC permission)
jobs:
publish:
runs-on: ubuntu-latest
steps:
- run: deno publish
# after
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: denoland/setup-deno@v2
- run: deno publish Defensive patterns
Strategy: validation
Validate before calling
function canAuthenticate(): boolean {
const hasToken = Deno.args.some((a) => a.startsWith('--token='));
const hasOidc =
Deno.env.get('GITHUB_ACTIONS') === 'true' &&
!!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_URL') &&
!!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_TOKEN');
return hasToken || hasOidc;
}
if (!canAuthenticate()) throw new Error('deno publish has no auth method'); Type guard
const hasOidcEnv = (): boolean =>
Deno.env.get('GITHUB_ACTIONS') === 'true' &&
!!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_URL') &&
!!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_TOKEN'); Try / catch
try {
await runDeno(['publish', ...(token ? ['--token', token] : [])]);
} catch (e) {
if (String(e.message).includes('No means to authenticate')) {
// fall back to prompting for a token or failing with setup instructions
}
} Prevention
- Give publish jobs `permissions: id-token: write` in GitHub Actions.
- Store a JSR token as a masked secret and pass `--token` as a CI fallback.
- Assert auth availability (token present or both ACTIONS_ID_TOKEN_REQUEST_* vars) before invoking publish.
When it happens
Trigger: Running `deno publish` locally without `--token`; running in a GitHub Actions workflow whose job lacks `permissions: id-token: write`, so the runner does not inject `ACTIONS_ID_TOKEN_REQUEST_*`; a reusable workflow/step that strips env vars.
Common situations: First publish from a laptop (no token configured); CI workflow copied from a non-publish job with default `permissions: contents: read`, which suppresses the OIDC vars; runners where the OIDC endpoint is disabled by organization policy.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Automatic provenance is only available in GitHub Actions
- Provenance generation in Github Actions requires 'id-token'
- Not running in GitHub Actions
- Failed to get OIDC token: status {}, response: '{}'
- Found {} problem{}
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/47e24cb27ac4201d.
Report an issue: GitHub.