A malicious page open in an administrator's browser could post to http://jenkins.example.com/job/deploy/build, and the browser would attach the session cookie. Jenkins 8,793 therefore demands a crumb with every state-changing POST: a token from /crumbIssuer, tied to the web session that fetched it. Since Jenkins 2.222 the UI has no switch to turn this off, and requests authenticated with an API token are exempt, because no browser sends one on its own:
PASS=$(cat ~/v5-ch5/.secrets/jenkins-admin); B=$J/job/sec-hello/build
code() { curl -s -o /dev/null -w '%{http_code}\n' "$@"; }
echo "password, no crumb: $(code -u "admin:$PASS" -X POST $B)"
echo "API token, no crumb: $(code -u "admin:$JENKINS_TOKEN" -X POST $B)"
CRUMB=$(curl -s -c jar -u "admin:$PASS" $J/crumbIssuer/api/json | jq -r .crumb)
echo "crumb, no session: $(code -u "admin:$PASS" -H "Jenkins-Crumb: $CRUMB" -X POST $B)"
echo "crumb + session: $(code -b jar -u "admin:$PASS" -H "Jenkins-Crumb: $CRUMB" -X POST $B)"Output
password, no crumb: 403 API token, no crumb: 201 crumb, no session: 403 crumb + session: 201
The first 403 page says "No valid crumb was included in the request". Scripts should authenticate with API tokens, as this chapter's do; a script that insists on a password must keep the cookie jar with its crumb.