Skip to content
jwtcodec

JWT code examples

Creating, verifying and decoding an HS256 token with the most popular library for each language. Paste any token they print into the decoder with the secret a-string-secret-at-least-256-bits-long to verify it.

JWT in Node.js / JavaScript

Install: npm install jose

jose works in Node.js, browsers, Deno, Bun and edge runtimes.

import { SignJWT, jwtVerify, decodeJwt } from "jose";

const secret = new TextEncoder().encode("a-string-secret-at-least-256-bits-long");

// Create and sign
const token = await new SignJWT({ name: "Ada Lovelace", admin: true })
  .setProtectedHeader({ alg: "HS256" })
  .setSubject("1234567890")
  .setIssuedAt()
  .setExpirationTime("1h")
  .sign(secret);
console.log(token);

// Verify (checks the signature and exp/nbf)
const { payload } = await jwtVerify(token, secret, { algorithms: ["HS256"] });
console.log(payload.name); // "Ada Lovelace"

// Decode WITHOUT verifying — never trust these claims
console.log(decodeJwt(token));

JWT in Python

Install: pip install pyjwt

import datetime as dt
import jwt

secret = "a-string-secret-at-least-256-bits-long"
now = dt.datetime.now(dt.timezone.utc)

# Create and sign
token = jwt.encode(
    {"sub": "1234567890", "name": "Ada Lovelace", "iat": now, "exp": now + dt.timedelta(hours=1)},
    secret,
    algorithm="HS256",
)
print(token)

# Verify (raises jwt.ExpiredSignatureError, jwt.InvalidSignatureError, ...)
claims = jwt.decode(token, secret, algorithms=["HS256"])
print(claims["name"])

# Decode WITHOUT verifying
print(jwt.decode(token, options={"verify_signature": False}))

JWT in Java

Install: io.jsonwebtoken:jjwt-api, jjwt-impl and jjwt-jackson (0.12.x)

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;

public class JwtExample {
    public static void main(String[] args) {
        SecretKey key = Keys.hmacShaKeyFor(
            "a-string-secret-at-least-256-bits-long".getBytes(StandardCharsets.UTF_8));

        // Create and sign (HS256 is picked from the key size)
        String token = Jwts.builder()
            .subject("1234567890")
            .claim("name", "Ada Lovelace")
            .issuedAt(new Date())
            .expiration(new Date(System.currentTimeMillis() + 3_600_000))
            .signWith(key)
            .compact();
        System.out.println(token);

        // Verify and read the claims
        Claims claims = Jwts.parser()
            .verifyWith(key)
            .build()
            .parseSignedClaims(token)
            .getPayload();
        System.out.println(claims.get("name", String.class));
    }
}

JWT in C# / .NET

Install: dotnet add package Microsoft.IdentityModel.JsonWebTokens

using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;

var key = new SymmetricSecurityKey(
    Encoding.UTF8.GetBytes("a-string-secret-at-least-256-bits-long"));
var handler = new JsonWebTokenHandler();

// Create and sign
string token = handler.CreateToken(new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(new[]
    {
        new Claim("sub", "1234567890"),
        new Claim("name", "Ada Lovelace"),
    }),
    Expires = DateTime.UtcNow.AddHours(1),
    SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256),
});
Console.WriteLine(token);

// Verify
var result = await handler.ValidateTokenAsync(token, new TokenValidationParameters
{
    ValidateIssuer = false,   // set ValidIssuer / ValidAudience in real apps
    ValidateAudience = false,
    IssuerSigningKey = key,
});
Console.WriteLine(result.IsValid ? result.Claims["name"] : result.Exception.Message);

JWT in Go

Install: go get github.com/golang-jwt/jwt/v5

package main

import (
    "fmt"
    "time"

    "github.com/golang-jwt/jwt/v5"
)

func main() {
    secret := []byte("a-string-secret-at-least-256-bits-long")

    // Create and sign
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "sub":  "1234567890",
        "name": "Ada Lovelace",
        "iat":  time.Now().Unix(),
        "exp":  time.Now().Add(time.Hour).Unix(),
    })
    signed, err := token.SignedString(secret)
    if err != nil {
        panic(err)
    }
    fmt.Println(signed)

    // Verify — always pin the expected algorithm
    parsed, err := jwt.Parse(signed, func(t *jwt.Token) (any, error) {
        return secret, nil
    }, jwt.WithValidMethods([]string{"HS256"}))
    if err != nil {
        panic(err)
    }
    claims := parsed.Claims.(jwt.MapClaims)
    fmt.Println(claims["name"])
}

JWT in PHP

Install: composer require firebase/php-jwt

<?php
require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$secret = 'a-string-secret-at-least-256-bits-long';

// Create and sign
$token = JWT::encode([
    'sub'  => '1234567890',
    'name' => 'Ada Lovelace',
    'iat'  => time(),
    'exp'  => time() + 3600,
], $secret, 'HS256');
echo $token, "\n";

// Verify (throws on a bad signature or expired token)
$decoded = JWT::decode($token, new Key($secret, 'HS256'));
echo $decoded->name, "\n";

JWT in Rust

Install: cargo add jsonwebtoken@9 serde --features serde/derive

use jsonwebtoken::{decode, encode, get_current_timestamp, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    name: String,
    exp: u64,
}

fn main() -> Result<(), jsonwebtoken::errors::Error> {
    let secret = b"a-string-secret-at-least-256-bits-long";
    let claims = Claims {
        sub: "1234567890".into(),
        name: "Ada Lovelace".into(),
        exp: get_current_timestamp() + 3600,
    };

    // Create and sign
    let token = encode(&Header::new(Algorithm::HS256), &claims, &EncodingKey::from_secret(secret))?;
    println!("{token}");

    // Verify
    let data = decode::<Claims>(&token, &DecodingKey::from_secret(secret), &Validation::new(Algorithm::HS256))?;
    println!("{}", data.claims.name);
    Ok(())
}

JWT in Bash

Decodes only — it does not verify the signature. Needs jq for pretty output.

# Decode part N of a JWT (1 = header, 2 = payload)
jwt_part() {
  local part
  part=$(cut -d. -f"$2" <<< "$1" | tr '_-' '/+')
  while (( ${#part} % 4 )); do part+="="; done
  base64 -d <<< "$part"
}

TOKEN='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature'
jwt_part "$TOKEN" 1 | jq .   # header
jwt_part "$TOKEN" 2 | jq .   # payload

Verification checklist

  • Always pass an explicit list of allowed algorithms. Never let the token's own alg decide.
  • Reject alg: none tokens.
  • Check exp, nbf, and the expected iss and aud.
  • Use secrets of at least 256 bits for HS256 and keep them out of source control.