Decode a JWT
A JWT looks readable the moment you paste it into any decoder — that's the point of the format — but reading the header and payload tells you nothing about whether the token is genuine. This API splits both jobs apart: decode the claims instantly, and separately confirm the signature really was issued with your key, not just copied from a legitimate-looking token.
Run — free
Runs in your browser. Free, unlimited — your data never leaves this page.
Decoding and verifying are two different questions
Because a JSON Web Token is only base64url-encoded, not encrypted, anyone can paste the middle section into a browser console and read the claims — that part requires no secret and proves nothing. Verification is the real question: does the signature match what your issuer would have produced with its private or shared key? Conflating the two is a common source of authentication bugs, which is exactly why this endpoint treats them as separate, explicit inputs.
How the request works
POST /dev/jwt-decode with the token and, if you want signature verification, the corresponding secret (for HS256) or public key (for RS256/ES256). The task runs async and returns a task_id right away; the decoded header, payload claims, expiry status and a clear valid/invalid signature verdict arrive by signed webhook or a signed link good for 24 hours.
The format's origin, briefly
JWTs were standardized in RFC 7519 in 2015 to give distributed systems a compact, self-contained way to pass claims between parties without a round trip to a central session store. That statelessness is also their main foot-gun: a token that decodes cleanly can still be expired, issued by the wrong party, or signed with an algorithm your service never intended to trust, which is why decoding alone should never be mistaken for authentication.
Where teams plug this in
This endpoint gets called from debugging tools that need to inspect a customer's token during a support ticket, from backend services validating tokens issued by a separate identity provider, from test suites asserting that claims like exp, aud and role are set correctly, and from log pipelines that need to extract a user ID from an access token without running a full auth middleware stack.
What comes back
The response separates the header, the payload and the verification result so your code never has to guess which part is which. Malformed tokens, missing keys or unsupported algorithms return a clear error instead of a silent failure, and because failed tasks are never billed, you can safely probe malformed input while debugging without worrying about cost.
What you can do with it
Support ticket debugging
Paste a customer's expired or rejected token to see its exact claims and expiry without writing a throwaway script.
Cross-service token validation
Verify tokens issued by an external identity provider before your backend trusts the claims inside them.
Automated test assertions
Check in CI that issued tokens carry the correct audience, issuer and role claims before a release ships.
Log and analytics enrichment
Extract a user or tenant ID from an access token during log processing without loading a full auth library.
FAQ
Does decoding a JWT require the secret key?
No, reading the header and payload only requires the token itself; the secret or public key is only needed if you also want signature verification.
Which signing algorithms can this JWT decoder verify?
HS256 with a shared secret, and RS256 or ES256 with a public key, covering the algorithms most identity providers issue by default.
Is the JWT decoder API free to use?
The tool above runs free in your browser. The API is paid — each call draws from your prepaid ForHosting KIT balance: top up from $10.00 (it never expires), pay each request's published price, and a call with no balance returns HTTP 402. No subscription, no tokens, and a failed task is never charged.
How much does decoding or verifying a token cost?
$0.002 per request whether you're just decoding claims or also verifying the signature, and failed tasks are never charged.
Can this tell me if my token has expired?
Yes, the response includes the expiry status alongside the decoded claims, so you don't need to compute it yourself from the exp field.
Is it safe to send production tokens to this API?
Tokens and keys are used only to process that single request and are deleted after the retention window, never used for training.
What happens with a malformed or truncated token?
The API returns a clear, specific error identifying which part failed to parse rather than a generic failure.
How is the result delivered?
Via a signed webhook, recommended for automated flows, or a signed link that stays valid for 24 hours.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev/jwt-decode \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"items":["valor-1","valor-2"]}'const res = await fetch("https://api.kit.forhosting.com/dev/jwt-decode", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"items": [
"valor-1",
"valor-2"
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev/jwt-decode",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"items": [
"valor-1",
"valor-2"
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev/jwt-decode", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"items":["valor-1","valor-2"]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"items":["valor-1","valor-2"]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev/jwt-decode", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"items": [
"valor-1",
"valor-2"
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev.jwt_decode",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |