step crypto jwt: Sign and Verify JWTs
step crypto jwt sign builds a signed JWT from claims and a key, and step crypto jwt verify checks one against the expected issuer, audience, and key.
When a pipeline needs a JWT for a machine-to-machine call, step crypto jwt avoids writing signing code. It uses JOSE under the hood with clear flags for the standard claims.
What it does
step crypto jwt sign reads claims (from flags or stdin) and signs them with the key from --key using the algorithm in --alg, printing a compact JWT. verify validates the signature and the --iss/--aud/--sub claims, exiting non-zero on any mismatch.
Common usage
step crypto jwt sign --key priv.pem --alg ES256 \
--iss ci --aud api --sub build-123 --exp $(date -d '+5 min' +%s)
# verify
echo "$JWT" | step crypto jwt verify \
--key pub.pem --iss ci --aud apiOptions
| Flag | What it does |
|---|---|
| --key <file> | Signing (sign) or verification (verify) key |
| --alg <alg> | JWS algorithm, e.g. ES256, RS256, HS256 |
| --iss / --aud / --sub | Issuer, audience, and subject claims |
| --exp <unix> | Expiry as a Unix timestamp |
| --nbf <unix> | Not-before timestamp |
In CI
Set --exp to a few minutes out so a leaked token is short-lived. verify checks --iss and --aud, so always pass the values you expect rather than trusting whatever the token carries.
Common errors in CI
"validation failed: square/go-jose: error in cryptographic primitive" means the wrong key or --alg for the token. "invalid audience claim (aud)" or "invalid issuer claim (iss)" means the token's claim does not match what you passed to verify. "token is expired" means --exp already passed; widen the window or re-sign.