> For the complete documentation index, see [llms.txt](https://quantumphp.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://quantumphp.gitbook.io/docs/packages/jwt/contracts.md).

# Contracts

This page covers the runtime behaviors you can rely on when integrating with `Quantum\Jwt\JwtToken`.

## Construction contract

```php
use Quantum\Jwt\JwtToken;

$jwt = new JwtToken();
$custom = new JwtToken('signing-secret');
```

Behavior:

* without an argument, the constructor reads `APP_KEY` through the Environment package
* with an argument, that string becomes the signing and verification key for the instance
* the same key is used for both `compose()` and `retrieve()`

If `APP_KEY` cannot be resolved, construction fails before you can issue or verify tokens.

## Payload contract

A token can only be composed after at least one payload entry has been added.

Accepted write methods:

* `setClaim(string $key, mixed $value)`
* `setClaims(array $claims)`
* `setData(array $data)`

`setData()` always writes to the `data` claim.

If no payload has been added, `compose()` throws `JwtException::payloadNotFound()`.

## Signing contract

```php
$token = $jwt->compose($keyId, $header);
```

Behavior:

* payload is signed with the instance key and current algorithm
* `$keyId` is optional and is forwarded to the encoded token header as `kid`
* `$header` is optional and is forwarded as custom JWT header fields

The package does not validate header contents itself.

## Algorithm contract

`setAlgorithm()` stores the provided string and returns the same instance.

The package does not validate algorithm names up front. Practical effect:

* invalid or unsupported values are accepted by `setAlgorithm()`
* failures happen later inside `firebase/php-jwt` when `compose()` or `retrieve()` runs

## Verification contract

```php
$payload = $jwt->retrieve($token)->fetchPayload();
```

Behavior:

* `retrieve()` verifies the token with the current instance key and algorithm
* on success, the decoded payload is stored on the instance
* `fetchPayload()` returns that decoded payload object
* `fetchData()` returns the `data` claim as an array, or `null` when the claim is absent
* `fetchClaim()` returns one decoded claim value, or `null` when the claim is absent

The package does not rename or normalize claims.

## Failure surface

`JwtToken` only throws its own package exception for one case:

* empty payload on `compose()`

Signing and verification failures from bad algorithms, invalid signatures, expired tokens, malformed tokens, or unsupported headers come from `firebase/php-jwt` directly.

Handle those upstream exceptions at your application boundary when you verify untrusted tokens.

## Instance state contract

`JwtToken` is stateful.

Practical effect:

* claims added through `setClaim()`, `setClaims()`, and `setData()` stay on the object until you overwrite them or discard the instance
* `retrieve()` updates the stored decoded payload, but it does not clear the compose-side payload array
* using a fresh `JwtToken` instance per token flow is the safest default


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://quantumphp.gitbook.io/docs/packages/jwt/contracts.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
