Backend Development Multi-Tool Workflow 2026-04-18

JWT + Timestamp API Debugging Workflow

Decode JWT tokens, convert Unix timestamps to human-readable dates, and debug API authentication issues. Essential workflow for troubleshooting auth failures with code examples.

The Problem

Your API returns 401 Unauthorized and you need to figure out why. The JWT token looks valid but something is wrong — maybe it is expired, has incorrect claims, or the payload is malformed. Debugging requires decoding the token, checking timestamps, and inspecting the JSON payload, which involves multiple separate steps.

Why This Workflow Matters

JWT authentication failures are one of the most common API debugging scenarios. Tokens contain encoded claims with Unix timestamps that are hard to read, Base64-encoded payloads that need decoding, and nested JSON that needs formatting. A systematic debugging workflow reduces mean time to resolution from hours to minutes.

Workflow Overview

Step-by-Step Instructions

1

Decode the JWT token

Paste the full JWT (header.payload.signature) into the JWT Decoder. It splits the token into its three parts and decodes the Base64url-encoded header and payload without needing the signing key.

2

Check token expiry timestamps

Copy the exp (expiration), iat (issued at), and nbf (not before) values from the decoded payload. Paste each into the Timestamp Converter to see the human-readable dates. Compare with current time.

3

Inspect the full payload

Copy the decoded payload JSON and paste it into the JSON Formatter. Check all claims: iss (issuer), aud (audience), sub (subject), scope or roles. Look for mismatches with your API configuration.

4

Verify Base64 encoding integrity

If the token looks corrupted, manually decode each segment with the Base64 Encoder (using Base64url variant). This catches truncation from URL encoding, copy-paste errors, or incorrect padding.

Before & After

Opaque JWT, unclear why auth fails

HTTP 401 Unauthorized
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOi...

# What went wrong? Is it expired? Wrong audience?
# Is the payload even valid JSON?

Decoded JWT with timestamp analysis

Header: {"alg": "RS256"} ✓
Payload: {"sub": "user1", "exp": 1713440000}
Expiry: 2024-04-18T12:00:00Z — EXPIRED 2 hours ago ✗
Fix: Refresh the token or extend TTL in auth config

Automate This Workflow

Copy these scripts to automate the workflow in your preferred language:

$ Bash
# Decode JWT without a library
TOKEN="eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMSIsImV4cCI6MTcxMzQ0MDAwMH0.sig"

# Split and decode payload (part 2)
PAYLOAD=$(echo "$TOKEN" | cut -d. -f2)
# Add padding and decode
echo "$PAYLOAD" | tr '_-' '/+' | base64 -d 2>/dev/null | jq '.'

# Check expiry
EXP=$(echo "$PAYLOAD" | tr '_-' '/+' | base64 -d 2>/dev/null | jq -r '.exp')
NOW=$(date +%s)
if [ "$EXP" -lt "$NOW" ]; then
  echo "TOKEN EXPIRED $(( (NOW - EXP) / 3600 )) hours ago"
  echo "Expired at: $(date -d @$EXP 2>/dev/null || date -r $EXP)"
else
  echo "Token valid for $(( (EXP - NOW) / 60 )) more minutes"
fi
Py Python
import json
import base64
from datetime import datetime, timezone

def decode_jwt(token: str) -> dict:
    """Decode JWT without verification (for debugging only)."""
    parts = token.split(".")
    if len(parts) != 3:
        raise ValueError("Invalid JWT format")

    # Decode header and payload (Base64url)
    def b64_decode(s):
        s += "=" * (4 - len(s) % 4)  # Add padding
        return json.loads(base64.urlsafe_b64decode(s))

    header = b64_decode(parts[0])
    payload = b64_decode(parts[1])
    return {"header": header, "payload": payload}

# Decode and check
token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMSIsImV4cCI6MTcxMzQ0MDAwMH0.sig"
result = decode_jwt(token)
print(json.dumps(result, indent=2))

# Check expiry
exp = result["payload"].get("exp")
if exp:
    exp_dt = datetime.fromtimestamp(exp, tz=timezone.utc)
    now = datetime.now(timezone.utc)
    if exp_dt < now:
        print(f"EXPIRED {now - exp_dt} ago")
    else:
        print(f"Valid for {exp_dt - now}")
JS Node.js
// Decode JWT without verification (debugging only)
function decodeJwt(token) {
  const [header, payload] = token.split(".").slice(0, 2)
    .map(part => {
      const padded = part + "=".repeat((4 - part.length % 4) % 4);
      return JSON.parse(
        Buffer.from(padded, "base64url").toString()
      );
    });
  return { header, payload };
}

const token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMSIsImV4cCI6MTcxMzQ0MDAwMH0.sig";
const { header, payload } = decodeJwt(token);
console.log("Algorithm:", header.alg);
console.log("Subject:", payload.sub);

// Check expiry
if (payload.exp) {
  const expDate = new Date(payload.exp * 1000);
  const now = new Date();
  if (expDate < now) {
    const hoursAgo = Math.round((now - expDate) / 3600000);
    console.log(`EXPIRED ${hoursAgo} hours ago`);
  } else {
    const minsLeft = Math.round((expDate - now) / 60000);
    console.log(`Valid for ${minsLeft} minutes`);
  }
}

Frequently Asked Questions

Is it safe to decode JWTs in the browser?
Yes — decoding a JWT does not require the signing key. The header and payload are just Base64url-encoded JSON, readable by anyone. The signature is what provides integrity verification. Never expose your signing key, but decoding for inspection is completely safe.
What are the most common JWT authentication failures?
In order of frequency: (1) expired token (exp in the past), (2) wrong audience (aud mismatch), (3) clock skew between servers, (4) wrong algorithm (alg mismatch), (5) malformed token (truncated during URL encoding). This workflow catches all five.
How do I handle JWT clock skew between servers?
Add a clock skew tolerance of 30-60 seconds when validating exp and nbf claims. Most JWT libraries support a clockTolerance or leeway option. Use NTP to synchronize clocks across your servers to minimize the issue.
Should I decode JWTs on the client or server side?
Decode on both. Client-side decoding (without verification) is useful for displaying user info and checking expiry before making API calls. Server-side verification (with the signing key) is mandatory for authorization decisions. Never trust client-decoded claims for access control.

Related Workflows

Try These Tools Now

All tools in this workflow are free and work directly in your browser — no sign-up required.