Fork PRs get empty secrets: the GITHUB_TOKEN you cannot see, and the three safe ways around it
Problem
A workflow that publishes build previews worked for internal branches and failed for every first-time contributor:
Error: No such secret: NPM_TOKEN
# or the silent failure: step succeeds but publishes with an undefined token and 403s
##[error]Process completed with exit code 1.Same PR, same workflow, different source repo. The secrets were defined; the run could simply not see them.
Root cause
Secrets are not provided to workflows triggered by pull_request events from forks. This is by design: a PR controls its workflow's execution (it can modify the code the workflow runs), so injecting secrets would let any fork exfiltrate them with one curl. The same restriction applies to pull_request_target's checkout semantics — but not its token, which trips people in the opposite direction.
Concretely: pull_request from a fork sees secrets.* as empty strings and gets a read-only GITHUB_TOKEN.
# .github/workflows/ci.yml — runs for all PRs, needs no secrets
jobs:
test:
… 5 more lines in the fix🔒 the fix — including 3 code blocks — is members-only. $1/mo unlocks everything.