Back
extracted
jsonwebtoken
v9.0.2
MIT

decode (from jsonwebtoken)

A vendorable decode-only bundle extracted from jsonwebtoken and jws. Useful when you only inspect JWT payloads locally and do not want the full package or its broader dependency graph.

Why copy this?

This page ships a decode-only bundle cut from jsonwebtoken and jws. The point is to keep the common payload-inspection path local without vendoring sign, verify, crypto, or the full dependency graph.

Native alternative: There is no direct native JWT decode helper. The built-in Buffer API can decode token segments, but this snippet preserves jsonwebtoken's decode contract and complete-option behavior.

Note: This snippet only decodes and parses JWT contents. It does not verify signatures, enforce claims, or make security decisions safe by itself.

This copy is your responsibility once you adopt it. It does not automatically receive upstream bug fixes or security updates.

Snippet
Copy-first distribution
Normalized
ESM / TS / normalized
Runtime: node, bun
/**
 * Derived from [email protected]
 * Rule-based normalized variant generated by this repository.
 * Preserve the upstream license and attribution notices when copying this file.
 */
/**
 * Derived from [email protected]
 * Rule-based normalized variant generated by this repository.
 * See THIRD_PARTY_NOTICES.md for upstream license and attribution details.
 */
var Buffer = require("buffer").Buffer;

function toString(obj) {
  if (typeof obj === "string") {
    return obj;
  }
  if (typeof obj === "number" || Buffer.isBuffer(obj)) {
    return obj.toString();
  }
  return JSON.stringify(obj);
}

var JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/;

function isObject(thing) {
  return Object.prototype.toString.call(thing) === "[object Object]";
}

function safeJsonParse(thing) {
  if (isObject(thing)) {
    return thing;
  }
  try {
    return JSON.parse(thing);
  } catch (e) {
    return undefined;
  }
}

function headerFromJWS(jwsSig) {
  var encodedHeader = jwsSig.split(".", 1)[0];
  return safeJsonParse(Buffer.from(encodedHeader, "base64").toString("binary"));
}

function signatureFromJWS(jwsSig) {
  return jwsSig.split(".")[2];
}

function payloadFromJWS(jwsSig, encoding) {
  encoding = encoding || "utf8";
  var payload = jwsSig.split(".")[1];
  return Buffer.from(payload, "base64").toString(encoding);
}

function isValidJws(string) {
  return JWS_REGEX.test(string) && !!headerFromJWS(string);
}

function jwsDecode(jwsSig, opts) {
  opts = opts || {};
  jwsSig = toString(jwsSig);

  if (!isValidJws(jwsSig)) {
    return null;
  }

  var header = headerFromJWS(jwsSig);
  if (!header) {
    return null;
  }

  var payload = payloadFromJWS(jwsSig);
  if (header.typ === "JWT" || opts.json) {
    payload = JSON.parse(payload, opts.encoding);
  }

  return {
    header: header,
    payload: payload,
    signature: signatureFromJWS(jwsSig),
  };
}

export default function (jwt, options) {
  options = options || {};
  var decoded = jwsDecode(jwt, options);
  if (!decoded) {
    return null;
  }
  var payload = decoded.payload;

  if (typeof payload === "string") {
    try {
      var obj = JSON.parse(payload);
      if (obj !== null && typeof obj === "object") {
        payload = obj;
      }
    } catch (e) {}
  }

  if (options.complete === true) {
    return {
      header: decoded.header,
      payload: payload,
      signature: decoded.signature,
    };
  }
  return payload;
}
Variant note: Decode-only bundle normalized for copy-paste into modern TS projects. It intentionally excludes verify and sign behavior.
Transforms: module.exports-to-export-default, js-extension-to-ts-extension, bundled-upstream-helper
Validation: This normalized variant is intended to stay oxlint and oxfmt clean in this repo.
Raw
CJS / JS / raw
Runtime: node, bun
var Buffer = require('buffer').Buffer;

function toString(obj) {
  if (typeof obj === 'string') {
    return obj;
  }
  if (typeof obj === 'number' || Buffer.isBuffer(obj)) {
    return obj.toString();
  }
  return JSON.stringify(obj);
}

var JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/;

function isObject(thing) {
  return Object.prototype.toString.call(thing) === '[object Object]';
}

function safeJsonParse(thing) {
  if (isObject(thing)) {
    return thing;
  }
  try {
    return JSON.parse(thing);
  } catch (e) {
    return undefined;
  }
}

function headerFromJWS(jwsSig) {
  var encodedHeader = jwsSig.split('.', 1)[0];
  return safeJsonParse(Buffer.from(encodedHeader, 'base64').toString('binary'));
}

function signatureFromJWS(jwsSig) {
  return jwsSig.split('.')[2];
}

function payloadFromJWS(jwsSig, encoding) {
  encoding = encoding || 'utf8';
  var payload = jwsSig.split('.')[1];
  return Buffer.from(payload, 'base64').toString(encoding);
}

function isValidJws(string) {
  return JWS_REGEX.test(string) && !!headerFromJWS(string);
}

function jwsDecode(jwsSig, opts) {
  opts = opts || {};
  jwsSig = toString(jwsSig);

  if (!isValidJws(jwsSig)) {
    return null;
  }

  var header = headerFromJWS(jwsSig);
  if (!header) {
    return null;
  }

  var payload = payloadFromJWS(jwsSig);
  if (header.typ === 'JWT' || opts.json) {
    payload = JSON.parse(payload, opts.encoding);
  }

  return {
    header: header,
    payload: payload,
    signature: signatureFromJWS(jwsSig)
  };
}

module.exports = function (jwt, options) {
  options = options || {};
  var decoded = jwsDecode(jwt, options);
  if (!decoded) {
    return null;
  }
  var payload = decoded.payload;

  if (typeof payload === 'string') {
    try {
      var obj = JSON.parse(payload);
      if (obj !== null && typeof obj === 'object') {
        payload = obj;
      }
    } catch (e) {}
  }

  if (options.complete === true) {
    return {
      header: decoded.header,
      payload: payload,
      signature: decoded.signature
    };
  }
  return payload;
};
Variant note: Single-file CommonJS bundle preserving jsonwebtoken decode behavior only.