Scripting & Automation
JWT-HACK is designed to work well in scripts and automated workflows. Use the
global --json flag to get machine-readable output for any command.
Exit Codes and Result Detection
Important: JWT-HACK does not signal outcomes like "signature invalid" or "secret not found" through exit codes. Commands such as
decode,verify, andcrackstill exit0in those cases — the result is reported in the output, not the status code. Do not branch onjwt-hack verify ...succeeding/failing.
Observed exit codes:
- 0 - The command ran (this includes "token invalid" and "secret not found")
- 1 - A hard error while producing
--jsonoutput, or a config/runtime failure - 2 - Invalid command-line arguments (from argument parsing)
To detect results reliably, use --json and inspect the response fields:
# verify → parse the "valid" boolean
jwt-hack --json verify "$TOKEN" --secret="$SECRET" | jq -e '.valid == true'
# crack → "found" is true and "value" holds the secret
jwt-hack --json crack -w wordlist.txt "$TOKEN" | jq -e '.found == true'
Bash Scripting
Basic Token Validation
#!/bin/bash
validate_token() {
local token="$1"
local secret="$2"
# verify exits 0 even for an invalid signature, so check the JSON "valid" field.
if [ "$(jwt-hack --json verify "$token" --secret="$secret" | jq -r '.valid')" = "true" ]; then
echo "Token is valid"
return 0
else
echo "Token is invalid"
return 1
fi
}
# Usage
if validate_token "$JWT_TOKEN" "$SECRET"; then
echo "Proceeding with authenticated request"
else
echo "Authentication failed"
exit 1
fi
Batch Token Processing
#!/bin/bash
# Process multiple tokens from file
while IFS= read -r token; do
echo "Processing token: ${token:0:20}..."
if jwt-hack decode "$token" > /dev/null 2>&1; then
echo "✓ Valid format"
jwt-hack decode "$token" | grep -E "(exp|iat)"
else
echo "✗ Invalid format"
fi
echo "---"
done < tokens.txt
Automated Cracking
#!/bin/bash
crack_token() {
local token="$1"
local wordlist="$2"
echo "Attempting to crack token..."
# crack exits 0 whether or not a secret is found, so check the JSON output.
local json secret
json=$(jwt-hack --json crack -w "$wordlist" "$token")
if [ "$(echo "$json" | jq -r '.found')" = "true" ]; then
secret=$(echo "$json" | jq -r '.value')
echo "SUCCESS: Secret found: $secret"
return 0
else
echo "FAILED: Could not crack token"
return 1
fi
}
# Try multiple wordlists
wordlists=("/usr/share/wordlists/rockyou.txt" "custom.txt" "common.txt")
for wordlist in "${wordlists[@]}"; do
if [[ -f "$wordlist" ]]; then
echo "Trying wordlist: $wordlist"
if crack_token "$JWT_TOKEN" "$wordlist"; then
break
fi
fi
done
Python Integration
Using subprocess
import subprocess
import json
import sys
def decode_jwt(token):
"""Decode a JWT and return the parsed JSON result, or None on error."""
result = subprocess.run(
['jwt-hack', '--json', 'decode', token],
capture_output=True, text=True
)
data = json.loads(result.stdout or '{}')
return data if data.get('success') else None
def verify_jwt(token, secret):
"""Verify a JWT signature. Returns True only if the JSON `valid` field is true."""
result = subprocess.run(
['jwt-hack', '--json', 'verify', token, '--secret', secret],
capture_output=True, text=True
)
data = json.loads(result.stdout or '{}')
return bool(data.get('valid'))
# Usage
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
if decode_result := decode_jwt(token):
print("Token decoded successfully")
print(decode_result)
else:
print("Failed to decode token")
sys.exit(1)
Note: jwt-hack does not use exit codes to report an invalid signature or a failed crack — always pass
--jsonand inspect the response fields (valid,found,value, …) rather than relying oncheck=True.
Token Analysis Pipeline
#!/usr/bin/env python3
import subprocess
import json
import re
from pathlib import Path
class JWTAnalyzer:
def __init__(self):
self.jwt_hack = "jwt-hack"
def _run_json(self, *args):
"""Run a jwt-hack subcommand with --json and return the parsed result."""
result = subprocess.run(
[self.jwt_hack, '--json', *args],
capture_output=True, text=True
)
return json.loads(result.stdout or '{}')
def decode(self, token):
"""Decode JWT and return the structured JSON result."""
data = self._run_json('decode', token)
return data if data.get('success') else None
def verify(self, token, secret):
"""Verify JWT signature via the JSON `valid` field."""
data = self._run_json('verify', token, '--secret', secret)
return bool(data.get('valid'))
def crack(self, token, wordlist):
"""Attempt to crack the JWT secret; returns the secret or None."""
data = self._run_json('crack', '-w', wordlist, token)
return data.get('value') if data.get('found') else None
def generate_payloads(self, token, target='all'):
"""Generate attack payloads (returns the JSON payload list)."""
return self._run_json('payload', token, '--target', target)
# Usage example
analyzer = JWTAnalyzer()
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Analyze token
info = analyzer.decode(token)
if info:
print("Token analysis:", info)
# Try to crack it
secret = analyzer.crack(token, "wordlist.txt")
if secret:
print(f"Secret found: {secret}")
# Verify with found secret
if analyzer.verify(token, secret):
print("Secret verified!")
CI/CD Integration
GitHub Actions
name: JWT Security Check
on: [push, pull_request]
jobs:
jwt-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install JWT-HACK
run: |
cargo install jwt-hack
- name: Analyze JWT tokens in code
run: |
# Find JWT tokens in code (simple regex)
grep -r "eyJ[A-Za-z0-9_-]*\." . || true
- name: Test JWT security
run: |
# Test any hardcoded tokens
if [ -f "test-tokens.txt" ]; then
while read token; do
echo "Testing token: $token"
jwt-hack decode "$token"
jwt-hack crack -w common-passwords.txt "$token" || true
done < test-tokens.txt
fi
Docker Integration
FROM rust:1.75 as builder
RUN cargo install jwt-hack
FROM debian:bookworm-slim
COPY --from=builder /usr/local/cargo/bin/jwt-hack /usr/local/bin/
COPY scripts/ /scripts/
ENTRYPOINT ["/scripts/analyze.sh"]
Configuration Management
Environment-Based Configuration
jwt-hack itself does not read these values from the environment, so read them into shell variables and pass them explicitly as flags:
#!/bin/bash
# Set defaults from environment (your own variables, not read by jwt-hack)
SECRET="${SECRET:-default-secret}"
WORDLIST="${WORDLIST:-/usr/share/wordlists/rockyou.txt}"
CONCURRENCY="${CONCURRENCY:-$(nproc)}"
# Pass them explicitly on the command line
jwt-hack verify "$token" --secret="$SECRET"
jwt-hack crack -w "$WORDLIST" -c "$CONCURRENCY" "$token"
Config File Generation
#!/bin/bash
# Generate jwt-hack config
mkdir -p ~/.config/jwt-hack
cat > ~/.config/jwt-hack/config.toml << EOF
default_secret = "${DEFAULT_SECRET}"
default_algorithm = "${DEFAULT_ALGORITHM:-HS256}"
default_wordlist = "${DEFAULT_WORDLIST}"
default_private_key = "${DEFAULT_PRIVATE_KEY}"
EOF
echo "Configuration generated at ~/.config/jwt-hack/config.toml"