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.