# JWT Decoder, Base64, Hash and HMAC Toolkit (`firebrick_zamia/jwt-hash-encoding-toolkit`) Actor

Decode JWTs without a network call (expiry, claims, warnings, optional HS256/384/512 check), Base64/Base64URL encode and decode, and MD5/SHA/SHA-3 hashes and HMAC. Pure compute.

- **URL**: https://apify.com/firebrick_zamia/jwt-hash-encoding-toolkit.md
- **Developed by:** [Aadam Ahmed](https://apify.com/firebrick_zamia) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## JWT Decoder, Base64 Encoder, SHA/MD5 Hash and HMAC Tool

**Decode a JWT online in bulk (header, claims, expiry, warnings, optional HS256/384/512 signature check), Base64 / Base64URL encode and decode, and compute MD5, SHA-1, SHA-2, SHA-3 hashes and HMAC. No web calls, no AI.**

### What you get

One result per input string with `ok`, `error` and the operation's fields: decoded `header` / `payload`, ISO `claim_times`, `expired`, `signature_verified` and `warnings` for JWTs; `output` for Base64; `digest` for hash and HMAC.

### Use cases

- Inspect many JWTs at once: which have expired, which use `alg: none`, which lack `exp`.
- Check an HS256 token against a test secret.
- Base64 / Base64URL conversion and file-checksum style hashing inside pipelines or AI-agent workflows.
- Generate HMAC signatures for webhook testing.

Small developer utilities as one cheap, deterministic call, with **no web calls and no AI model**. Useful in data pipelines and for AI agents, because Apify Actors can be called through Apify's MCP server (https://mcp.apify.com).

Operations (one billed result per input string):

- **jwt_decode**: read the header and payload of a JWT, convert `exp` / `nbf` / `iat` to ISO times, tell whether it is expired at a reference time, and warn about `alg: none`, a missing `exp`, an empty signature or non-numeric dates. If you supply a secret, HS256 / HS384 / HS512 signatures are checked in constant time.
- **base64_encode / base64_decode**: standard Base64 and URL-safe Base64URL (padding optional on decode). Binary results are reported as hex with `is_utf8: false`.
- **hash**: MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-512 as hex, base64 or base64url.
- **hmac**: the same algorithms keyed with your secret.

### Input

| Field | Meaning |
|---|---|
| `items` | Strings, one per line (up to 10,000, each up to 100,000 characters) |
| `operation` | `jwt_decode` (default), `base64_encode`, `base64_decode`, `hash`, `hmac` |
| `algorithm`, `outputEncoding` | for `hash` and `hmac` |
| `secret` | HMAC key, or optional JWT verification key. Marked secret in the input form and never echoed in output |
| `urlSafe` | Base64 encode with the URL-safe alphabet and no padding |
| `referenceTime` | ISO time used for the expiry check; empty means now |

### Example input and output

Input (bundled `test-input.json`): the public jwt.io sample token, `operation: jwt_decode`, `secret: your-256-bit-secret`, `referenceTime: 2026-10-22T10:00:00Z`. Real output of the bundled test input (the public jwt.io sample token, secret `your-256-bit-secret`, reference time 22 Oct 2026):

```json
{
  "index": 0, "operation": "jwt_decode", "ok": true, "error": null,
  "algorithm": "HS256", "type": "JWT",
  "header": { "alg": "HS256", "typ": "JWT" },
  "payload": { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 },
  "claim_times": { "iat": "2018-01-18T01:30:22.000Z" },
  "expired": null, "signature_present": true, "signature_verified": true,
  "warnings": ["no exp claim: the token never expires"]
}
```

### Limitations (read before relying on it)

- **Decoding is not trust.** Without a secret, `jwt_decode` does not verify anything: anyone can forge a payload. `signature_verified` is `null` unless you give a secret and the token uses HS256, HS384 or HS512. RS256, ES256, PS256, EdDSA and other asymmetric algorithms are **not verified** (no public-key input). `alg: none` tokens are never reported as verified. See RFC 7519 (https://www.rfc-editor.org/rfc/rfc7519) and RFC 8725 (https://www.rfc-editor.org/rfc/rfc8725).
- **Encrypted tokens (JWE, 5 parts) cannot be read**; the Actor says so.
- **Do not paste live production tokens or secrets** into a run you do not control: inputs are stored in your run's storage and logs on Apify. Use test tokens or rotate afterwards.
- **MD5 and SHA-1 are broken for security purposes**; they are provided for checksums and legacy interoperability. **A plain hash is not a safe way to store passwords**; this Actor has no bcrypt, scrypt or Argon2.
- Text is hashed and encoded as UTF-8. Expiry uses the comparison `now >= exp` (RFC 7519 section 4.1.4); no clock-skew leeway is applied.
- Implemented with Node's built-in `node:crypto`; outputs for the standard test vectors (RFC 4648, RFC 4231, FIPS examples) are checked in the repository's tests.

### Pricing (pay per result)

Pay-per-event with Apify's built-in dataset-item event: each input string is one result. The live price is set in Apify Console and shown on the Store page (see Store). Planning figure in our notes: USD 1.00 per 1,000 results. The one hash Actor with a visible price found is listed from USD 0.00025 per hash (USD 0.25 per 1,000, https://apify.com/hipersoft/hash-generator); see `apify/RESEARCH-3.md` for the competitor snapshot.

### FAQ

**Does it call a website, API or AI model?** No. Everything is computed locally.

**Can it verify RS256 / ES256 JWTs?** Not in this version.

**Is the secret stored?** It is part of your run input, so it is stored by Apify like any input; it is not written to the output dataset.

**What does `hash` return for `hello` with `sha256`?** The hex digest `2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824` (produced by the actor's code). `base64_encode` of `hello` gives `aGVsbG8=`.

**Is JWT decoding the same as validation?** No. See the first limitation.

# Actor input Schema

## `items` (type: `array`):

Strings to process, one per line (up to 10,000, each up to 100,000 characters). Each item is one billed result.

## `operation` (type: `string`):

What to do with every item: decode a JWT, Base64 encode or decode, hash, or HMAC.

## `algorithm` (type: `string`):

Algorithm for the hash and hmac operations. MD5 and SHA-1 are broken for security use; they are offered for checksums and legacy systems.

## `outputEncoding` (type: `string`):

How the hash or HMAC digest is written.

## `secret` (type: `string`):

HMAC key for the hmac operation. For jwt_decode it optionally verifies HS256, HS384 and HS512 signatures. Never echoed in the output.

## `urlSafe` (type: `boolean`):

Base64 encode: use the URL-safe alphabet (- and \_) without padding, as used in JWTs.

## `referenceTime` (type: `string`):

ISO 8601 time used to decide whether a JWT is expired (for example 2026-10-22T10:00:00Z). Leave empty to use the current time.

## Actor input object example

```json
{
  "items": [
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
  ],
  "operation": "jwt_decode",
  "algorithm": "sha256",
  "outputEncoding": "hex",
  "urlSafe": false
}
```

# Actor output Schema

## `results` (type: `string`):

All result records.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "items": [
        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("firebrick_zamia/jwt-hash-encoding-toolkit").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "items": ["eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"] }

# Run the Actor and wait for it to finish
run = client.actor("firebrick_zamia/jwt-hash-encoding-toolkit").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "items": [
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
  ]
}' |
apify call firebrick_zamia/jwt-hash-encoding-toolkit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,firebrick_zamia/jwt-hash-encoding-toolkit"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ed85YAbiHSUPMhA10/builds/WtR9fMaJycbgr2eBY/openapi.json
