CI auth regression tests + JWKS rotation drift detection. Add 5 lines to your workflow.
# .github/workflows/jwt.yml
- uses: redbullhorns/jwtshield-ci@v1
with:
issuer: https://login.example.com
audience: api://backend
fail-on-severity: high /v1/validate/jwks-rotation
classifies key rotation between two snapshots as no_change,
safe_overlap,
overlap, or
disjoint. Catch the rotation
before in-flight tokens start failing.
/v1/test/auth-regression
runs your fixture suite on every PR. Scope renames, claim drops,
audience changes — caught before they reach staging. Negative
fixtures assert that broken tokens stay broken.
expected_failure_codes.read:invoices 9ms write:billing 11ms read:invoices_v2 — scope renamed without alias 12ms read:reports 10ms admin:users 13ms We track every disclosure, every CVE, every attack pattern. Default policy refuses all of them. Each refusal lands as a structured finding with a stable code — see /docs/errors for the full taxonomy.
No SDK to audit. No JWKS rotation to babysit. One HTTP call
to /v1/inspect/token
for decode, one to /v1/validate/jwt
for full validation.
# Inspect any JWT. Issue your API key at jwtshield.com/dashboard.
$ export JWTSHIELD_URL=https://api.jwtshield.com
$ export JWTSHIELD_API_KEY=jws_live_...
$ curl -sSf -X POST "$JWTSHIELD_URL/v1/inspect/token" \
-H "Authorization: Bearer $JWTSHIELD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"token":"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3JfMSJ9.x"}'// 1. Configure once
const BASE_URL = process.env.JWTSHIELD_URL;
const API_KEY = process.env.JWTSHIELD_API_KEY; // jws_live_...
// 2. Decode any JWT, structured response back
const r = await fetch(`${BASE_URL}/v1/inspect/token`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ token: bearer }),
});
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const { decoded, suspicious_warnings } = await r.json();
console.log(decoded.header, suspicious_warnings);import os, httpx
BASE_URL = os.environ["JWTSHIELD_URL"]
API_KEY = os.environ["JWTSHIELD_API_KEY"] # jws_live_...
r = httpx.post(
f"{BASE_URL}/v1/inspect/token",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"token": bearer},
timeout=10.0,
)
r.raise_for_status()
body = r.json()
print(body["decoded"]["header"], body["suspicious_warnings"])JWTShield v0.0.1 ships today. The items below are scoped and dated; until they ship, they are not features of JWTShield. We list them here so the live-state copy elsewhere on the site can be honest.
JWTShield v0.0.1 is live. Read the docs, decode any JWT in the browser, then sign in with one click and ship a verified key straight into your runtime.