JSON Web Tokens (JWTs) provide a compact way to carry authentication claims inside each HTTP request. Using cURL with JWT access tokens enables scripted access to protected APIs, integration tests, and automation workflows without exposing raw credentials on every call.
A typical API issues a JWT after validating credentials or a refresh token, usually returning a JSON object that contains fields such as token and refreshToken. Subsequent requests include the token in an Authorization header using the Bearer scheme, so the server can verify the signature and claims on each call before returning protected data.
Because JWTs are self-contained and often short-lived, handling them correctly means respecting token expiry, scopes, and revocation behavior. Using HTTPS, avoiding logging raw tokens, and storing values in environment variables or protected configuration files reduces leakage risk while still allowing repeatable cURL commands in terminals and scripts.
Steps to authenticate using JWT in cURL:
- Request a JWT from the authentication endpoint to obtain an access token as JSON.
$ curl --request POST \ --header "Content-Type: application/json" \ --data '{"username":"user","password":"pass"}' \ https://api.example.com/auth/login {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","expiresIn":3600}The authentication endpoint validates credentials and returns a signed JWT together with any refresh metadata.
- Store the access JWT value in a shell variable for reuse in subsequent commands.
$ TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." $ printf '%s\n' "$TOKEN" eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Persisting long-lived JWTs in shell history, shared terminals, or paste buffers increases the impact of credential theft.
- Capture the JWT automatically from the JSON response using jq to reduce manual copying.
$ TOKEN="$(curl --request POST \ --header 'Content-Type: application/json' \ --data '{"username":"user","password":"pass"}' \ https://api.example.com/auth/login | jq -r '.token')" $ printf '%s\n' "$TOKEN" eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...This pattern requires jq and keeps the token out of intermediate files and logs.
- Call a protected endpoint by sending the JWT as a Bearer token in the Authorization header.
$ curl --header "Authorization: Bearer $TOKEN" \ https://api.example.com/api/protected {"data":"protected content"}The Bearer schema is the conventional HTTP Authorization prefix for JWT access tokens.
- Inspect the HTTP status code to confirm that the token grants access to the protected resource.
$ curl --header "Authorization: Bearer $TOKEN" \ --write-out "%{http_code}\n" \ --silent \ --output /dev/null \ https://api.example.com/api/protected 200Status codes in the 2xx range indicate success, whereas 401 Unauthorized or 403 Forbidden usually signal missing, expired, or insufficiently scoped tokens.
- Detect expired or invalid tokens by observing authorization failures in repeated requests.
$ curl --header "Authorization: Bearer $TOKEN" \ --write-out "%{http_code}\n" \ --silent \ --output /dev/null \ https://api.example.com/api/protected 401Many APIs also return a JSON error body that includes fields such as error or message describing why authorization failed.
- Exchange a valid refresh token for a new access JWT using the refresh endpoint when expiry occurs.
$ NEW_TOKEN="$(curl --request POST \ --header "Content-Type: application/json" \ --data '{"refreshToken":"<your_refresh_token>"}' \ https://api.example.com/auth/refresh | jq -r '.token')" $ printf '%s\n' "$NEW_TOKEN" eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Storing the refreshed token in a separate variable simplifies rotation workflows and allows rollback while testing.
- Use the refreshed token in the Authorization header and enable verbose output to verify authenticated access.
$ TOKEN="$NEW_TOKEN" $ curl --header "Authorization: Bearer $TOKEN" \ --verbose \ https://api.example.com/api/protected > GET /api/protected HTTP/1.1 > Host: api.example.com > Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ##### snipped ##### < HTTP/1.1 200 OK
Success signals include presence of the Authorization header in verbose output and an HTTP status such as 200 OK from the protected endpoint.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
Comment anonymously. Login not required.
