# Introduction

> 

**unjwt** is a low-level JSON Web Token (JWT) library built entirely on the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). It gives you the pieces you need to sign, verify, encrypt, decrypt, and manage keys — nothing more, and nothing hidden.

## What it does

JWT is a portable, self-contained format for carrying data between systems — most commonly used for authentication tokens. A JWT is either:

- **Signed** (a [JWS](/jwt/jws)) — anyone can read the data, and you can prove it hasn't been tampered with.
- **Encrypted** (a [JWE](/jwt/jwe)) — only the holder of the right key can read the data.

Both forms are built on top of cryptographic **keys**, which unjwt represents as [JWKs](/jwk) (JSON Web Keys) — a standard way to serialize a key as a JSON object.

That's the whole library: [JWS](/jwt/jws) for signing, [JWE](/jwt/jwe) for encryption, [JWK](/jwk) for keys, and a small set of [utilities](/utilities).

## What it looks like

```ts
import { sign, verify } from "unjwt/jws";
import { generateJWK } from "unjwt/jwk";

const key = await generateJWK("HS256");

const token = await sign({ sub: "user_1" }, key, { expiresIn: "1h" });
// eyJhbGciOiJIUzI1NiIsImtpZCI6IjRjM2QiLCJ0eXAiOiJKV1QifQ...

const { payload } = await verify(token, key);
// { sub: "user_1", iat: 1736860800, exp: 1736864400 }
```

That's a complete round trip: generate a key, sign a token, verify it. No config files, no framework setup, no globals.

## Why it exists

The JOSE family of specs ([RFC 7515](https://www.rfc-editor.org/rfc/rfc7515), [RFC 7516](https://www.rfc-editor.org/rfc/rfc7516), [RFC 7517](https://www.rfc-editor.org/rfc/rfc7517), [RFC 7518](https://www.rfc-editor.org/rfc/rfc7518), [RFC 7519](https://www.rfc-editor.org/rfc/rfc7519)) is powerful but dense. Most applications only need a handful of functions out of the whole spec surface, but they need those functions to be correct by default.

unjwt aims for a short, readable API where:

- **Keys carry their own metadata.** If your JWK has `"alg": "RS256"`, you don't need to tell `sign()` or `verify()` which algorithm to use — the library reads it from the key.
- **Safe defaults go without saying.** PBES2 iterations default to [OWASP-recommended 600 000](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2); `verify()` validates JWT claims automatically when the payload is an object; algorithm allowlists are inferred from the key shape.
- **The full standard is still reachable.** General JSON Serialization for both [JWS](/jwt/jws/multi-signature) and [JWE](/jwt/jwe/multi-recipient), [PEM conversion](/jwk/pem), [ECDH-ES](/jwt/jwe/ecdh-es), JWK Sets with automatic key rotation — all first-class.

## Where to go next

- [Install unjwt](/getting-started/installation) and get your first token working.
- Read the [quickstart](/getting-started/quickstart) — a two-minute signed token, end to end.
- If the acronyms are new, skim [core concepts](/getting-started/core-concepts) first.

<note>

unjwt was originally visioned by [Johann Schopplich](https://github.com/johannschopplich), heavily inspired by [Filip Skokan's `jose`](https://github.com/panva/jose) internal cryptographic primitives, and initially sponsored by [JAMflow](https://jamflow.cloud) — thanks to all three for making this project possible.

</note>
