rusty_paseto 0.10.0

A type-driven, ergonomic alternative to JWT for secure stateless PASETO tokens.
Documentation
export const metadata = {
  title: 'PASETO vs JWT',
  description:
    'Learn why PASETO is a more secure alternative to JWT and when to use each.',
}

# PASETO vs JWT

PASETO (Platform-Agnostic Security Tokens) was designed to address the security pitfalls of JSON Web Tokens (JWT). This page explains the key differences and why you might choose PASETO. {{ className: 'lead' }}

## The Problem with JWT

JWT has been widely adopted but suffers from several design issues that have led to security vulnerabilities:

### Algorithm Confusion

JWT allows the token to specify which algorithm to use for verification. This has led to attacks where:

- Attackers change the algorithm header to "none" to bypass verification
- Attackers switch from RS256 to HS256 and use the public key as an HMAC secret

```json
// JWT header - algorithm is attacker-controlled
{
  "alg": "HS256",  // Could be changed to "none" or mismatched
  "typ": "JWT"
}
```

### Too Many Choices

JWT supports many algorithm combinations, making it easy to choose insecure options or misconfigure verification.

---

## How PASETO Solves These Problems

### No Algorithm Negotiation

PASETO tokens don't include algorithm information. The version and purpose completely determine the cryptographic algorithms used:

```
v4.local.base64-encoded-payload
^^ ^^^^^
|  |
|  Purpose (determines symmetric vs asymmetric)
Version (determines exact algorithms)
```

### Versioned Protocols

Each PASETO version specifies exact algorithms with no choices:

<Properties>
  <Property name="V4 Local">
    XChaCha20 + BLAKE2b-MAC (no negotiation possible)
  </Property>
  <Property name="V4 Public">
    Ed25519 signatures (no negotiation possible)
  </Property>
</Properties>

### Authenticated Encryption

PASETO Local tokens use authenticated encryption (AEAD), ensuring both confidentiality and integrity in a single operation.

---

## Feature Comparison

| Feature | JWT | PASETO |
|---------|-----|--------|
| Algorithm in token | Yes (attack vector) | No |
| Encryption built-in | No (requires JWE) | Yes (Local purpose) |
| Algorithm choices | Many (footgun) | None (version-determined) |
| "none" algorithm | Supported (dangerous) | Not possible |
| Footer/assertions | No | Yes |
| Key confusion attacks | Possible | Not possible |

---

## When to Use Each

### Use PASETO When

- Building new applications from scratch
- Security is a top priority
- You want simpler, harder-to-misuse APIs
- You don't need ecosystem compatibility

### Use JWT When

- Integrating with existing systems that require JWT
- Using third-party identity providers (OAuth, OIDC)
- Ecosystem compatibility is more important than security properties

---

## Migration Path

If you're currently using JWT and want to migrate to PASETO, rusty_paseto makes it straightforward:

<Row>
  <Col>

    **JWT (using jsonwebtoken crate):**

    ```rust
    use jsonwebtoken::{encode, Header, EncodingKey};

    let token = encode(
        &Header::default(),
        &claims,
        &EncodingKey::from_secret(key),
    )?;
    ```

  </Col>
  <Col>

    **PASETO (using rusty_paseto):**

    ```rust
    use rusty_paseto::prelude::*;

    let token = PasetoBuilder::<V4, Local>::default()
        .set_claim(SubjectClaim::from("user"))
        .build(&key)?;
    ```

  </Col>
</Row>

The PASETO approach eliminates the need to specify algorithms and provides compile-time guarantees about the token format.