Artifactory returned HTTP 401 because the jf CLI sent no valid credential. The request reached the server, but JF_ACCESS_TOKEN (or the legacy API key) was empty, unset in the step, or expired.
What this error means
A jf rt upload, jf rt download, or jf config add step fails with "401 Unauthorized" or "Bad credentials". Public reads may work while authenticated operations fail.
Diagnose it: registry, auth, and version resolution
Terminal
# which registry is actually in effect, and with what credentials?
<pkg-tool> config list 2>/dev/null | grep -iE "registry|auth|token"
# does the exact version resolve from the runner?
<pkg-tool> view <package> versions 2>&1 | tail -3
Common causes
JF_ACCESS_TOKEN was never exposed to the step
The token lives in a repository secret but the env var was not set on the job or step, so the jf CLI authenticates anonymously and Artifactory returns 401.
The access token has expired
JFrog access tokens carry an expiry. Once past it, every authenticated call returns 401 until a fresh token is issued and stored as the secret.
How to fix it
Provide JF_URL and JF_ACCESS_TOKEN via secrets
Store the Artifactory base URL and an access token as repository or organization secrets.
Expose them as JF_URL and JF_ACCESS_TOKEN in the step env so setup-jfrog-cli configures the CLI automatically.
Keep JF_ACCESS_TOKEN in CI secrets, never committed to the repo.
Prefer long-lived reference tokens or OIDC over short expiries for CI.
Verify auth early with jf rt ping before upload or download steps.
Frequently asked questions
What causes JFrog "401 Unauthorized" (JF_ACCESS_TOKEN) in CI?
There are 2 common causes: jf_access_token was never exposed to the step and the access token has expired. The token lives in a repository secret but the env var was not set on the job or step, so the jf CLI authenticates anonymously and Artifactory returns 401.
How do I fix JFrog "401 Unauthorized" (JF_ACCESS_TOKEN) in CI?
There are 2 fixes depending on which cause you have: provide jf_url and jf_access_token via secrets and rotate an expired token. Work through them in order, since the first is the most common.
What does JFrog "401 Unauthorized" (JF_ACCESS_TOKEN) in CI actually mean?
A jf rt upload, jf rt download, or jf config add step fails with "401 Unauthorized" or "Bad credentials".
How do I stop JFrog "401 Unauthorized" (JF_ACCESS_TOKEN) in CI happening again?
Keep JF_ACCESS_TOKEN in CI secrets, never committed to the repo. The prevention section lists 3 changes that keep it from recurring.