Skip to content

How to decode a JWT (read claims) without verifying the signature

Real snippets to extract JWT header/payload (Base64URL) and read claims. Useful for debugging; not a replacement for verification.

← Developer Zone
Updated: 2026-03-22

Use this article when...

This section is built for speed: one concrete task, multiple stacks, and the minimum context needed not to copy the wrong thing.

Use this after capturing the real payload

Work from the request or response body that actually failed instead of rebuilding JSON from memory.

Pick the language that matches the incident

The useful path here is fast adaptation: choose your stack, then copy only after reading the notes around parsing and formatting.

Validate the result with the tool

Once the snippet runs, inspect the live payload with JSON Formatter or the related tool to confirm the structure is really fixed.

What this article gives you

A short path from incident to implementation: context, language-specific snippets, and the warning signs that usually get skipped.

Languages

13

Related tools

3

Topics

jwt, auth, security, debugging

Decoding a JWT means “reading it”: split header.payload.signature, Base64URL-decode it, and parse JSON. This helps you inspect exp/nbf, iss, aud, scopes/roles, and custom claims.

Important: decoding does NOT validate the signature. If a token comes from a client, never trust its payload without verification on the server.

Dependency snapshot by language

Check this first to see which snippets use built-in/runtime APIs and which ones need external packages before you start copying code.

Bash
External

Node.js.

C#
Built-in

Built-in or runtime API

Delphi
Check notes

Review the notes for setup details.

Go
Built-in

Built-in or runtime API

Java
Built-in

Built-in or runtime API

JavaScript
Built-in

Built-in or runtime API

Kotlin
Built-in

Built-in or runtime API

PHP
Check notes

Review the notes for setup details.

Python
Built-in

Built-in or runtime API

Ruby
Built-in

Built-in or runtime API

Rust
Check notes

Review the notes for setup details.

TypeScript
Built-in

Built-in or runtime API

VB.NET
Built-in

Built-in or runtime API

How to use these code examples well

The snippet is only the fast path. The explanation and notes are what keep you from copying the wrong assumption into production.

1. Start with the problem

Make sure the article really matches the issue you are debugging before copying code just because the title looks close.

2. Read the notes

That is where portability limits, dependency requirements, and runtime assumptions usually appear.

3. Validate the output

If the code runs but the bug remains, jump to the related tool and inspect the real payload, token, timestamp, or config.

Code examples by language

Snippets that compile/run, plus short explanations and real-world notes.

Bash

bash
Bash
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature"
TOKEN="$TOKEN" node -e "const t=process.env.TOKEN; const [h,p]=t.split("."); console.log(Buffer.from(h,"base64url").toString("utf8")); console.log(Buffer.from(p,"base64url").toString("utf8"));"
Explanation

Uses Node.js to reliably Base64URL-decode from the terminal and print header and payload as JSON.

Notes
  • Dependency: Node.js.
  • This does not verify signature; it is read-only for debugging.

C#

csharp
C#
using System;
using System.Text;
using System.Text.Json;

static byte[] Base64UrlDecode(string input) {
  var s = input.Replace('-', '+').Replace('_', '/');
  switch (s.Length % 4) {
    case 2: s += "=="; break;
    case 3: s += "="; break;
  }
  return Convert.FromBase64String(s);
}

var token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature";
var parts = token.Split('.');
var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(parts[0]));
var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(parts[1]));
using var header = JsonDocument.Parse(headerJson);
using var payload = JsonDocument.Parse(payloadJson);
Console.WriteLine(JsonSerializer.Serialize(header, new JsonSerializerOptions { WriteIndented = true }));
Console.WriteLine(JsonSerializer.Serialize(payload, new JsonSerializerOptions { WriteIndented = true }));
Explanation

Converts Base64URL → bytes, decodes UTF-8, and parses JSON. Useful to inspect claims quickly while debugging.

Notes
  • System.Text.Json (std).
  • Do not use this as security validation: verification is missing.

Delphi

delphi
Delphi
program JwtDecode;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.NetEncoding;

function Base64UrlToBase64(const S: string): string;
var
  T: string;
begin
  T := StringReplace(S, "-", "+", [rfReplaceAll]);
  T := StringReplace(T, "_", "/", [rfReplaceAll]);
  while (Length(T) mod 4) <> 0 do
    T := T + "=";
  Result := T;
end;

var
  Token: string;
  Parts: TArray<string>;
  PayloadJson: string;

begin
  Token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature";
  Parts := Token.Split([Char(46)]);
  PayloadJson := TNetEncoding.Base64.Decode(Base64UrlToBase64(Parts[1]));
  Writeln(PayloadJson);
end.
Explanation

In Delphi, you convert Base64URL to Base64 (replacements + padding) and decode using TNetEncoding.Base64. The result is the payload JSON ready to inspect.

Notes
  • Std: System.NetEncoding.
  • No signature verification; debugging only.

Go

go
Go
package main

import (
  "encoding/base64"
  "encoding/json"
  "fmt"
  "strings"
)

func main() {
  token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature"
  parts := strings.Split(token, ".")
  payloadBytes, err := base64.RawURLEncoding.DecodeString(parts[1])
  if err != nil {
    panic(err)
  }
  var v any
  if err := json.Unmarshal(payloadBytes, &v); err != nil {
    panic(err)
  }
  pretty, _ := json.MarshalIndent(v, "", "  ")
  fmt.Println(string(pretty))
}
Explanation

RawURLEncoding handles Base64URL without padding. Then parse JSON and print it indented.

Notes
  • Std.
  • For verification you need a JWT library + keys (and validate exp/iss/aud).

Java

java
Java
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Main {
  public static void main(String[] args) {
    String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature";
    String payload = token.split("\\.")[1];
    byte[] decoded = Base64.getUrlDecoder().decode(payload);
    System.out.println(new String(decoded, StandardCharsets.UTF_8));
  }
}
Explanation

Base64.getUrlDecoder() decodes Base64URL. Printing the payload JSON is useful to inspect claims quickly.

Notes
  • Std.
  • To parse JSON in Java you typically use Jackson/Gson (dependencies).

JavaScript

javascript
JavaScript
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature";
const payload = token.split(".")[1];
const json = Buffer.from(payload, "base64url").toString("utf8");
console.log(JSON.stringify(JSON.parse(json), null, 2));
Explanation

In Node.js, Buffer supports base64url. Decode, parse JSON, and print it formatted.

Notes
  • Node.js.
  • No verification: inspection only.

Kotlin

kotlin
Kotlin
import java.nio.charset.StandardCharsets
import java.util.Base64

fun main() {
  val token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature"
  val payload = token.split(".")[1]
  val decoded = Base64.getUrlDecoder().decode(payload)
  println(String(decoded, StandardCharsets.UTF_8))
}
Explanation

Kotlin/JVM uses java.util.Base64 URL-safe decoder to get the payload JSON.

Notes
  • Std.
  • For pretty print/parsing, use a JSON library (dependency).

PHP

php
PHP
<?php
$token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature";
$payload = explode(".", $token)[1];
$payload = strtr($payload, "-_", "+/");
$payload .= str_repeat("=", (4 - strlen($payload) % 4) % 4);
$json = base64_decode($payload, true);
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
echo json_encode($data, JSON_PRETTY_PRINT) . PHP_EOL;
Explanation

Normalize Base64URL to Base64 (replacements + padding), decode and parse JSON. Great to inspect claims.

Notes
  • JSON_THROW_ON_ERROR (PHP 7.3+).
  • Decode ≠ verify: do not treat this as security.

Python

python
Python
import base64
import json

token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature"
payload_b64 = token.split(".")[1]
raw = base64.urlsafe_b64decode(payload_b64 + "==")
obj = json.loads(raw.decode("utf-8"))
print(json.dumps(obj, indent=2, ensure_ascii=False))
Explanation

Base64URL is decoded with urlsafe_b64decode (adding padding if needed). Then parse the payload JSON.

Notes
  • Std.
  • If you need verification, use a JWT library and validate exp/iss/aud.

Ruby

ruby
Ruby
require "base64"
require "json"

token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature"
payload = token.split(".")[1]
json = Base64.urlsafe_decode64(payload)
obj = JSON.parse(json)
puts JSON.pretty_generate(obj)
Explanation

Base64.urlsafe_decode64 handles Base64URL. Then JSON.parse and pretty_generate to print readable claims.

Notes
  • Std.
  • No signature verification.

Rust

rust
Rust
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
use serde_json::Value;

fn main() {
  let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature";
  let payload = token.split(".").nth(1).unwrap();
  let bytes = URL_SAFE_NO_PAD.decode(payload).unwrap();
  let v: Value = serde_json::from_slice(&bytes).unwrap();
  println!("{}", serde_json::to_string_pretty(&v).unwrap());
}
Explanation

The URL_SAFE_NO_PAD engine decodes Base64URL without padding. Then parse JSON and print it nicely.

Notes
  • Dependencies: base64 = "0.22", serde_json = "1".

TypeScript

ts
TypeScript
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature";
const payload = token.split(".")[1];
const json = Buffer.from(payload, "base64url").toString("utf8");
console.log(JSON.stringify(JSON.parse(json) as unknown, null, 2));
Explanation

In Node.js, Buffer supports base64url. This is the most direct way to read payloads in TS scripts.

Notes
  • Node.js.
  • Decode ≠ verify.

VB.NET

vbnet
VB.NET
Imports System
Imports System.Text
Imports System.Text.Json

Module Program
  Private Function Base64UrlDecode(input As String) As Byte()
    Dim s = input.Replace("-", "+").Replace("_", "/")
    Select Case (s.Length Mod 4)
      Case 2 : s &= "=="
      Case 3 : s &= "="
    End Select
    Return Convert.FromBase64String(s)
  End Function

  Sub Main()
    Dim token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9.signature"
    Dim parts = token.Split("."c)
    Dim payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(parts(1)))
    Using doc = JsonDocument.Parse(payloadJson)
      Console.WriteLine(JsonSerializer.Serialize(doc, New JsonSerializerOptions With {.WriteIndented = True}))
    End Using
  End Sub
End Module
Explanation

Converts Base64URL to Base64 (replacements + padding), decodes UTF-8, and parses JSON to print readable claims.

Notes
  • System.Text.Json (std).
  • No signature verification.

Related tools

Use the tool when you need to generate or validate output fast.

Trust and privacy

Copy/paste-friendly by design. Still, treat real production secrets carefully.

  • Prefer synthetic examples when sharing screens or recording.
  • Do not paste real API keys, tokens, or personal data unless you fully trust your environment.
  • If you need ordering, do not use UUID v4 as a sortable id: add createdAt or use sortable ids.