{"record":{"id":"47e24cb27ac4201d","repo":"denoland/deno","slug":"no-means-to-authenticate-pass-a-token-to-token-47e24c","errorCode":null,"errorMessage":"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","messagePattern":"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","errorType":"exception","errorClass":"AnyError","httpStatus":null,"severity":"error","filePath":"cli/tools/publish/auth.rs","lineNumber":36,"sourceCode":"}\n\npub(crate) fn is_gha() -> bool {\n  std::env::var(\"GITHUB_ACTIONS\").unwrap_or_default() == \"true\"\n}\n\npub(crate) fn gha_oidc_token() -> Option<String> {\n  std::env::var(\"ACTIONS_ID_TOKEN_REQUEST_TOKEN\")\n    .ok()\n    .filter(|s| !s.is_empty())\n}\n\nfn get_gh_oidc_env_vars() -> Option<Result<(String, String), AnyError>> {\n  if std::env::var(\"GITHUB_ACTIONS\").unwrap_or_default() == \"true\" {\n    let url = std::env::var(\"ACTIONS_ID_TOKEN_REQUEST_URL\");\n    let token = std::env::var(\"ACTIONS_ID_TOKEN_REQUEST_TOKEN\");\n    match (url, token) {\n      (Ok(url), Ok(token)) => Some(Ok((url, token))),\n      (Err(_), Err(_)) => Some(Err(anyhow::anyhow!(\n        \"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\"\n      ))),\n      _ => None,\n    }\n  } else {\n    None\n  }\n}\n\npub fn get_auth_method(\n  maybe_token: Option<String>,\n  dry_run: bool,\n) -> Result<AuthMethod, AnyError> {\n  if dry_run {\n    // We don't authenticate in dry-run mode.\n    return Ok(AuthMethod::Interactive);\n  }\n","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/tools/publish/auth.rs#L18-L54","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (job without OIDC permission)\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n      - run: deno publish\n\n# after\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      id-token: write\n    steps:\n      - uses: denoland/setup-deno@v2\n      - run: deno publish","handlingStrategy":"validation","validationCode":"function canAuthenticate(): boolean {\n  const hasToken = Deno.args.some((a) => a.startsWith('--token='));\n  const hasOidc =\n    Deno.env.get('GITHUB_ACTIONS') === 'true' &&\n    !!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_URL') &&\n    !!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_TOKEN');\n  return hasToken || hasOidc;\n}\nif (!canAuthenticate()) throw new Error('deno publish has no auth method');","typeGuard":"const hasOidcEnv = (): boolean =>\n  Deno.env.get('GITHUB_ACTIONS') === 'true' &&\n  !!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_URL') &&\n  !!Deno.env.get('ACTIONS_ID_TOKEN_REQUEST_TOKEN');","tryCatchPattern":"try {\n  await runDeno(['publish', ...(token ? ['--token', token] : [])]);\n} catch (e) {\n  if (String(e.message).includes('No means to authenticate')) {\n    // fall back to prompting for a token or failing with setup instructions\n  }\n}","preventionTips":["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."],"tags":["publish","jsr","authentication","oidc","github-actions","token"],"backgroundTag":"missing-auth-credentials","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}