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

  1. In GitHub Actions add `permissions: id-token: write` to the publish job so the OIDC env vars are injected, enabling tokenless publishing.
  2. 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 }}`).
  3. 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

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

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/47e24cb27ac4201d. Report an issue: GitHub.