Decode a JWT
Paste a JWT and read what is inside: a sample token signed with HS256 reveals its subject, its name claim and an expiry of 13 September 2020, so it is flagged as expired. Decoding never verifies the signature. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
read the claims and verify the signature
Reading a token is not trusting it
A JWT is a compact way to pass claims between systems without asking a central session store each time. Its header and claims are only encoded, not encrypted, so any decoder can show them the moment you paste the token. That convenience is also the trap. A token that decodes cleanly may still be expired, may have been issued by the wrong party, or may be signed with an algorithm your service never intended to accept. Decoding answers what the token says; only checking the signature with the right key answers whether to believe it.
What the decoded result shows you
You see the header with the signing algorithm and type, and the claims with values such as the subject, a name, the issue time and the expiry time. The sample token, signed with HS256, expired at 1600000000, which the tool turns into 13 September 2020 at 12:26 UTC and flags as expired. That makes it quick to answer a support ticket about a rejected login, to confirm that a release issues tokens with the right audience, issuer and role, or to pull a user or tenant ID out of a log line.
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.
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
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.
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.
Does decoding a JWT prove that it is genuine?
No. A token is only encoded, not encrypted, so anyone can read its claims. A token that decodes cleanly can still be expired, come from the wrong issuer or be signed with an algorithm you never meant to trust.
What is decoding a token useful for?
Support work, for one: paste a customer's rejected token and see its exact claims and expiry without writing a throwaway script. It also helps check that issued tokens carry the right audience, issuer and role, or pull a user ID out of a log.
What are the three parts of a JWT?
They are separated by dots. The first is the header, which names the algorithm, such as HS256, and the type. The second holds the claims, such as the subject, name and expiry. The third is the signature, which only a key can check.
Related tools
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, by email and from Telegram — and soon from our app too.
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 '{"token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.c2ln"}'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({
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.c2ln"
})
});
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={
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.c2ln"
},
)
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" => '{"token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.c2ln"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.c2ln"}`)
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
{
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.c2ln"
}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. |
Technical notes
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.
Decoding and verifying are two different questions
Verification is the real question: does the signature match what your issuer would have produced with its private or shared key? 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. 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.
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
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. The response separates the header, the payload and the verification result so your code never has to guess which part is which.
Technical questions
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.
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.
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.