Skip to main content

JWT Claims Inspector and Decoder API

REAL DATA

Decode any compact JWS/JWT — header, payload, registered claims and exp/nbf/iat evaluated at a real or supplied clock. Signatures are never verified.

Authoritative reference data or standards computation

Base URL
/api/jwt
Capabilities
2 routes
Last updated
July 29, 2026
Data source

GET /api/jwt/decode

Base64url-decodes the header and payload, resolves the RFC 7519 registered claims and matches the remaining claim names against the IANA JSON Web Token Claims registry. The signature is checked for base64url wellformedness and measured, never decoded or verified.

Live requestRuns against the public API
No key required
GET/api/jwt/decode?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Request parameters

Compact JWS/JWT: three dot-separated unpadded base64url segments (RFC 7515 §3.1), at most 8,000 characters. Surrounding whitespace is trimmed; trailing bits that do not complete a byte are discarded, as base64url decoders do. Use disposable test tokens — never a production credential.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/jwt/decode?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
const res = await fetch("https://randomapi.dev/api/jwt/decode?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/jwt/decode?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/jwt/decode?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 1
token string required

Compact JWS/JWT: three dot-separated unpadded base64url segments (RFC 7515 §3.1), at most 8,000 characters. Surrounding whitespace is trimmed; trailing bits that do not complete a byte are discarded, as base64url decoders do. Use disposable test tokens — never a production credential.

allowed: ≤ 8000
example: token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=header,payload
exclude list

Return all fields except these (comma-separated).

example: exclude=claimRegistryMatches
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 9
header object

The JOSE header exactly as sent, including alg, typ, kid, cty and crit when present.

example: {"typ":"JWT","alg":"HS256"}

payload object

The JWT claims set exactly as sent. Duplicate member names collapse to the last occurrence.

example: {"iss":"joe","exp":1300819380,"http://example.com/is_root":true}

signaturePresent boolean

Whether the third segment is non-empty. False for an unsecured JWS (alg=none). Says nothing about validity.

example: true

signatureLength integer

Length of the third segment in base64url characters. The signature is never decoded, and a length that cannot encode whole octets (4n+1) is a 400 just as it is for the other two segments. It is not withheld, though: meta.params echoes the token you sent, signature included.

example: 43

segmentCount integer

Dot-separated segments in the token; always 3, since any other count is a 400.

example: 3

algorithm object

The alg header value with its IANA JOSE registry entry: name, family (this API's grouping of JWS signature algorithms — null for key-management, content-encryption and unregistered values), description, usage, requirements and whether it is registered at all.

example: {"name":"HS256","family":"HMAC","description":"HMAC using SHA-256","usage":"alg","requirements":"Required","registered":true}

registeredClaims object

All seven RFC 7519 §4.1 claims, always present as keys. Each carries present, value, JSON type and — for exp/nbf/iat — the NumericDate rendered as an ISO 8601 instant.

example: {"iss":{"present":true,"value":"joe","type":"string","instant":null},"exp":{"present":true,"value":1300819380,"type":"number","instant":"2011-03-22T18:43:00.000Z"}}

unregisteredClaims object[]

Every claim outside RFC 7519 §4.1, by name and JSON type only — values are already in payload and are not repeated here.

example: [{"name":"http://example.com/is_root","type":"boolean"}]

claimRegistryMatches object[]

The subset of unregisteredClaims that appears in the pinned IANA JSON Web Token Claims registry, with the registry's own description and reference.

example: [{"name":"scope","description":"Scope Values","reference":"RFC8693, Section 4.2"}]

Documented examples

Build-generated requests and complete responses
3
Decode the RFC 7519 example token
GET /api/jwt/decode?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
{
  "data": {
    "header": {
      "typ": "JWT",
      "alg": "HS256"
    },
    "payload": {
      "iss": "joe",
      "exp": 1300819380,
      "http://example.com/is_root": true
    },
    "signaturePresent": true,
    "signatureLength": 43,
    "segmentCount": 3,
    "algorithm": {
      "name": "HS256",
      "family": "HMAC",
      "description": "HMAC using SHA-256",
      "usage": "alg",
      "requirements": "Required",
      "registered": true
    },
    "registeredClaims": {
      "iss": {
        "present": true,
        "value": "joe",
        "type": "string",
        "instant": null
      },
      "sub": {
        "present": false,
        "value": null,
        "type": null,
        "instant": null
      },
      "aud": {
        "present": false,
        "value": null,
        "type": null,
        "instant": null"generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Inspect an access token's registry-known claims
GET /api/jwt/decode?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIwMzAtMDEifQ.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyXzQyIiwiYXVkIjpbImh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiaHR0cHM6Ly9hZG1pbi5leGFtcGxlLmNvbSJdLCJleHAiOjE4OTM0NTYwMDAsIm5iZiI6MTg5MzQ1MjQwMCwiaWF0IjoxODkzNDUyNDAwLCJqdGkiOiJqdGktOGMyZjE5YTQiLCJzY29wZSI6InJlYWQ6b3JkZXJzIHdyaXRlOm9yZGVycyIsImVtYWlsIjoiZGV2QGV4YW1wbGUuY29tIiwidGVuYW50IjoiYWNtZSJ9.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
{
  "data": {
    "header": {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "2030-01"
    },
    "payload": {
      "iss": "https://auth.example.com",
      "sub": "user_42",
      "aud": [
        "https://api.example.com",
        "https://admin.example.com"
      ],
      "exp": 1893456000,
      "nbf": 1893452400,
      "iat": 1893452400,
      "jti": "jti-8c2f19a4",
      "scope": "read:orders write:orders",
      "email": "dev@example.com",
      "tenant": "acme"
    },
    "signaturePresent": true,
    "signatureLength": 43,
    "segmentCount": 3,
    "algorithm": {
      "name": "RS256",
      "family": "RSASSA-PKCS1-v1_5",
      "description": "RSASSA-PKCS1-v1_5 using SHA-256",
      "usage": "alg",
      "requirements": "Recommended",
      "registered": true
    },
    "registeredClaims": {
      "iss": {
        "present": true,
        "value": "https://auth.example.com",
        "type": "string",
        "instant": null
      },
    …
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Report an unsecured alg=none token
GET /api/jwt/decode?token=eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.
{
  "data": {
    "header": {
      "alg": "none"
    },
    "payload": {
      "iss": "joe",
      "exp": 1300819380,
      "http://example.com/is_root": true
    },
    "signaturePresent": false,
    "signatureLength": 0,
    "segmentCount": 3,
    "algorithm": {
      "name": "none",
      "family": "none",
      "description": "No digital signature or MAC performed",
      "usage": "alg",
      "requirements": "Optional",
      "registered": true
    },
    "registeredClaims": {
      "iss": {
        "present": true,
        "value": "joe",
        "type": "string",
        "instant": null
      },
      "sub": {
        "present": false,
        "value": null,
        "type": null,
        "instant": null
      },
      "aud": {
        "present": false,
        "value": null,
        "type": null,
        "instant": null
      },
    …
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}

GET /api/jwt/claims

Evaluates the time-based registered claims against at (default: now) with optional clock skew, plus optional exact audience and issuer expectations. Still no signature verification.

Live requestRuns against the public API
No key required
GET/api/jwt/claims?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&at=2026-07-25T12%3A00%3A00Z

Request parameters

Compact JWS/JWT: three dot-separated unpadded base64url segments (RFC 7515 §3.1), at most 8,000 characters. Surrounding whitespace is trimmed; trailing bits that do not complete a byte are discarded, as base64url decoders do. Use disposable test tokens — never a production credential.

Instant to evaluate against, as YYYY-MM-DD or a timestamp such as 2026-07-25T12:00:00Z. Defaults to the current UTC instant, and the resolved value is echoed in meta.params.

Audience the caller expects. Compared to aud with exact, case-sensitive equality (any element for an array aud); whitespace is significant and is not trimmed. Omit to skip the check.

Issuer the caller expects. Compared to iss with exact, case-sensitive equality; whitespace is significant and is not trimmed. Omit to skip the check.

Tolerance in seconds (0–300) applied to the exp, nbf and iat comparisons — never to secondsUntilExpiry.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/jwt/claims?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&at=2026-07-25T12:00:00Z"
const res = await fetch("https://randomapi.dev/api/jwt/claims?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&at=2026-07-25T12:00:00Z");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/jwt/claims?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&at=2026-07-25T12:00:00Z").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/jwt/claims?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&at=2026-07-25T12:00:00Z"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 5
token string required

Compact JWS/JWT: three dot-separated unpadded base64url segments (RFC 7515 §3.1), at most 8,000 characters. Surrounding whitespace is trimmed; trailing bits that do not complete a byte are discarded, as base64url decoders do. Use disposable test tokens — never a production credential.

allowed: ≤ 8000
example: token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
at date

Instant to evaluate against, as YYYY-MM-DD or a timestamp such as 2026-07-25T12:00:00Z. Defaults to the current UTC instant, and the resolved value is echoed in meta.params.

example: at=2026-07-25T12:00:00Z
audience string

Audience the caller expects. Compared to aud with exact, case-sensitive equality (any element for an array aud); whitespace is significant and is not trimmed. Omit to skip the check.

allowed: 1 – 1024
example: audience=https://api.example.com
issuer string

Issuer the caller expects. Compared to iss with exact, case-sensitive equality; whitespace is significant and is not trimmed. Omit to skip the check.

allowed: 1 – 1024
example: issuer=https://auth.example.com
clockSkewSeconds int

Tolerance in seconds (0–300) applied to the exp, nbf and iat comparisons — never to secondsUntilExpiry.

default: 0
allowed: 0 – 300
example: clockSkewSeconds=60
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=at,expired
exclude list

Return all fields except these (comma-separated).

example: exclude=evaluation
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 9
at string (ISO 8601)

The instant every comparison below was made against, resolved from `at` or the request clock.

example: 2026-07-25T12:00:00.000Z

expired boolean nullable

True when the instant is at or after exp, after applying clock skew. Null when exp is absent, is not a JSON number, or lies outside the ±8,640,000,000,000-second instant range this API can represent — never guessed.

example: true

notYetValid boolean nullable

True when the instant is before nbf, after applying clock skew. Null when nbf is absent, is not a JSON number, or lies outside the ±8,640,000,000,000-second instant range this API can represent.

example: false

secondsUntilExpiry float (seconds) nullable

exp minus the evaluation instant, in seconds; negative once expired. Clock skew is deliberately not applied. Null when exp is unusable.

example: -484161420

issuedInFuture boolean nullable

True when iat is later than the instant plus clock skew — a sign of issuer clock drift. Null when iat is absent, is not a JSON number, or lies outside the ±8,640,000,000,000-second instant range this API can represent.

example: false

audienceMatches boolean nullable

Whether aud names the expected audience. Null when no audience parameter was supplied; false when the token has no usable aud.

example: null

issuerMatches boolean nullable

Whether iss equals the expected issuer. Null when no issuer parameter was supplied; false when the token has no usable iss.

example: null

clockSkewSeconds integer (0-300)

Tolerance actually applied to the exp, nbf and iat comparisons.

example: 0

evaluation object[]

Ordered trace of stable reason codes — always starting with signature.not-verified — each with the claim it concerns (null for the signature notice) and a human explanation.

example: [{"claim":null,"code":"signature.not-verified","detail":"This API never verifies signatures and accepts no key material, so nothing below is evidence that the token is authentic."},{"claim":"exp","code":"exp.expired","detail":"'exp' is 2011-03-22T18:43:00.000Z, at or before the evaluation instant even after 0s of skew."}]

Documented examples

Build-generated requests and complete responses
3
Evaluate an expired token at a fixed instant
GET /api/jwt/claims?token=eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&at=2026-07-25T12:00:00Z
{
  "data": {
    "at": "2026-07-25T12:00:00.000Z",
    "expired": true,
    "notYetValid": null,
    "secondsUntilExpiry": -484161420,
    "issuedInFuture": null,
    "audienceMatches": null,
    "issuerMatches": null,
    "clockSkewSeconds": 0,
    "evaluation": [
      {
        "claim": null,
        "code": "signature.not-verified",
        "detail": "This API never verifies signatures and accepts no key material, so nothing below is evidence that the token is authentic."
      },
      {
        "claim": "exp",
        "code": "exp.expired",
        "detail": "'exp' is 2011-03-22T18:43:00.000Z, at or before the evaluation instant even after 0s of skew."
      },
      {
        "claim": "nbf",
        "code": "nbf.absent",
        "detail": "The token has no 'nbf' claim, so it could not be evaluated."
      },
      {
        "claim": "iat",
        "code": "iat.absent",
        "detail": "The token has no 'iat' claim, so it could not be evaluated."
      },
      {
        "claim": "aud",
        "code": "aud.not-checked",
        "detail": "No 'audience' parameter was supplied, so 'aud' was not compared."
      },
      {
        "claim": "iss",
        "code": "iss.not-checked",
        "detail": "No 'issuer' parameter was supplied, so 'iss' was not compared.""generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Assert the audience and issuer of an access token
GET /api/jwt/claims?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIwMzAtMDEifQ.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyXzQyIiwiYXVkIjpbImh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiaHR0cHM6Ly9hZG1pbi5leGFtcGxlLmNvbSJdLCJleHAiOjE4OTM0NTYwMDAsIm5iZiI6MTg5MzQ1MjQwMCwiaWF0IjoxODkzNDUyNDAwLCJqdGkiOiJqdGktOGMyZjE5YTQiLCJzY29wZSI6InJlYWQ6b3JkZXJzIHdyaXRlOm9yZGVycyIsImVtYWlsIjoiZGV2QGV4YW1wbGUuY29tIiwidGVuYW50IjoiYWNtZSJ9.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&audience=https%3A%2F%2Fapi.example.com&issuer=https%3A%2F%2Fauth.example.com&at=2029-12-31T23:30:00Z
{
  "data": {
    "at": "2029-12-31T23:30:00.000Z",
    "expired": false,
    "notYetValid": false,
    "secondsUntilExpiry": 1800,
    "issuedInFuture": false,
    "audienceMatches": true,
    "issuerMatches": true,
    "clockSkewSeconds": 0,
    "evaluation": [
      {
        "claim": null,
        "code": "signature.not-verified",
        "detail": "This API never verifies signatures and accepts no key material, so nothing below is evidence that the token is authentic."
      },
      {
        "claim": "exp",
        "code": "exp.active",
        "detail": "'exp' is 2030-01-01T00:00:00.000Z, after the evaluation instant."
      },
      {
        "claim": "nbf",
        "code": "nbf.reached",
        "detail": "'nbf' is 2029-12-31T23:00:00.000Z, at or before the evaluation instant."
      },
      {
        "claim": "iat",
        "code": "iat.not-in-future",
        "detail": "'iat' is 2029-12-31T23:00:00.000Z, at or before the evaluation instant."
      },
      {
        "claim": "aud",
        "code": "aud.match",
        "detail": "'aud' names 'https://api.example.com'."
      },
      {
        "claim": "iss",
        "code": "iss.match",
        "detail": "'iss' is exactly 'https://auth.example.com'.""generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Allow 60 seconds of clock skew
GET /api/jwt/claims?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyXzQyIiwiZXhwIjoxODAwMDAwMDAwfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&at=2027-01-15T08:00:30Z&clockSkewSeconds=60
{
  "data": {
    "at": "2027-01-15T08:00:30.000Z",
    "expired": false,
    "notYetValid": null,
    "secondsUntilExpiry": -30,
    "issuedInFuture": null,
    "audienceMatches": null,
    "issuerMatches": null,
    "clockSkewSeconds": 60,
    "evaluation": [
      {
        "claim": null,
        "code": "signature.not-verified",
        "detail": "This API never verifies signatures and accepts no key material, so nothing below is evidence that the token is authentic."
      },
      {
        "claim": "exp",
        "code": "exp.active",
        "detail": "'exp' is 2027-01-15T08:00:00.000Z, after the evaluation instant."
      },
      {
        "claim": "nbf",
        "code": "nbf.absent",
        "detail": "The token has no 'nbf' claim, so it could not be evaluated."
      },
      {
        "claim": "iat",
        "code": "iat.absent",
        "detail": "The token has no 'iat' claim, so it could not be evaluated."
      },
      {
        "claim": "aud",
        "code": "aud.not-checked",
        "detail": "No 'audience' parameter was supplied, so 'aud' was not compared."
      },
      {
        "claim": "iss",
        "code": "iss.not-checked",
        "detail": "No 'issuer' parameter was supplied, so 'iss' was not compared.""generatedAt": "2026-07-29T08:13:22.000Z"
  }
}

About this API

Coverage & behavior

This endpoint never verifies signatures and accepts no key material. It base64url-decodes a compact JWS and reports what the token says; nothing it returns is evidence that a token is authentic, unmodified or authorized. It is a structure and claims inspector for test fixtures and CI assertions, not a security control. That is also why no field this API produces is named valid, and none ever will be — the only way valid can appear in a response is if your own token carries a claim by that name.

Do not put a production token in a URL. This endpoint is pure computation: it stores nothing, and randomapi.dev never writes a request's query string to an application log. What nobody can promise you is the path — query strings are routinely captured by proxies, browser history, CI job logs and edge request logs before they ever reach us. And like every parameter on this platform, the token you sent is echoed back verbatim in meta.params, signature included, so the response is exactly as sensitive as the request. Use throwaway fixtures.

/decode splits on . per RFC 7515 §3.1 and requires all three segments to be well-formed unpadded base64url — the right alphabet and a length that can encode whole octets — then base64url-decodes the first two, decodes them as UTF-8 and parses each as JSON, requiring both to be JSON objects. It returns the JOSE header verbatim — so alg, typ, kid, cty and crit appear exactly as sent — plus the claims set verbatim, the seven RFC 7519 §4.1 registered claims (with exp, nbf and iat also rendered as ISO 8601 instants), every other claim by name and JSON type, and the matching entries from a pinned snapshot of the IANA JSON Web Token Claims registry. The alg value is looked up in a pinned snapshot of the IANA JSON Web Signature and Encryption Algorithms registry. alg: "none" and a crit list are reported, never judged. The signature is never decoded or interpreted: data reports only signaturePresent and signatureLength.

/claims evaluates exp, nbf and iat as NumericDate values (RFC 7519 §2: seconds since the Unix epoch, ignoring leap seconds, non-integer values allowed) against at, which defaults to the current UTC instant and is echoed in meta.params. Following RFC 7519 §4.1.4 a token is expired once the instant is at or after exp; following §4.1.5 it is not-yet-valid while the instant is before nbf. clockSkewSeconds (0–300) widens both windows and is applied to iat too, but never to secondsUntilExpiry, which is the raw exp − at distance. Optional audience and issuer are compared to aud and iss with exact, case-sensitive equality — an array aud matches when any element is equal. expired, notYetValid and issuedInFuture are null, not false, whenever the underlying claim is absent, is not a JSON number, or falls outside the instant range this API can represent — the reason is never guessed. Every conclusion also appears as a stable code in evaluation, which always opens with signature.not-verified.

Scope limits, stated plainly. Five-segment JWE tokens are rejected with a 400 instead of half-decoded, because encrypted tokens cannot be read without the recipient's key. Only the compact serialization is supported: nested JWTs, detached payloads and the JWS JSON serializations are not. Duplicate JSON member names collapse to the last occurrence — the parser behavior RFC 7515 §4 explicitly permits for the header — and duplicates are not flagged in either segment. Tokens are capped at 8,000 characters and JSON nesting at 64 levels; a number literal that overflows to Infinity is a 400 rather than a silent null.

Use it for

  • Assert in CI that a fixture token expires at exactly the instant a test expects
  • Check a token's audience and issuer from a shell script with no JWT library installed
  • Find out which claims of an unfamiliar token are IANA-registered and which are vendor extensions
  • Reproduce a clock-skew bug by re-evaluating the same token at a pinned instant

Frequently asked questions

Does this API verify the JWT signature?

No. It never verifies signatures and accepts no key material, so a successful decode proves nothing about a token's authenticity or integrity. No field this API produces is named valid, because it cannot tell you that.

Is it safe to paste a production token into the URL?

No. The API stores nothing and never writes your query string to an application log, but query strings are routinely captured by proxies, browser history, CI job logs and edge request logs before they reach us. The response also echoes your token back in meta.params, signature and all, so it is exactly as sensitive as the request. Use disposable test tokens.

How do I check whether a token had expired at a specific moment?

Call /claims with at=2026-07-25T12:00:00Z. expired, secondsUntilExpiry and the evaluation trace are computed against that instant instead of the current clock, and clockSkewSeconds (0–300) adds tolerance.

Can it decode an encrypted JWE token?

No. A five-segment token returns 400 explaining that it is a JWE rather than a JWS, because encrypted tokens cannot be decoded without the recipient's key. Only the three-segment compact JWS is supported.

What does it do with alg=none or a crit header?

It reports them without judging them. The alg value is returned with its IANA registry entry, an unsecured JWS shows signaturePresent: false for its empty signature segment, and crit is returned verbatim inside header.

How does it match an aud claim that is an array?

audience matches when any element of the aud array is exactly equal to it, case-sensitively. A string aud is compared directly, and a token with no aud at all reports audienceMatches: false with the code aud.absent.

Standards & references