PASETO Token Anatomy — From String to Bytes
Detailed walkthrough of how a PASETO token is laid out on the wire, how each segment is encoded, and where the signature or auth tag lives inside the payload.
Detailed Explanation
Understanding the layout of a PASETO token byte-by-byte is the fastest way to debug issuance and verification bugs.
Top-level structure:
vN.purpose.<payload-segment>[.<footer-segment>]
There are 3 or 4 dot-separated parts. The first two — vN and purpose — are plain ASCII; everything else is Base64url with no padding.
Header segment:
The first two parts together form the header string that's bound into the cryptographic operation via pre-authentication encoding (PAE). Examples: v4.public, v4.local, v3.public, v2.local. There is no JSON header like JWT has — the header is the literal concatenation of the version and purpose strings.
Payload segment for public tokens:
After Base64url decoding, the payload segment for v*.public is the UTF-8 JSON message followed by the signature bytes. Signature lengths:
- v1.public: 256 bytes (RSA-PSS-2048)
- v2.public: 64 bytes (Ed25519)
- v3.public: 96 bytes (ECDSA P-384, raw R||S)
- v4.public: 64 bytes (Ed25519)
To extract the JSON, decode the segment and slice off the trailing N bytes.
Payload segment for local tokens:
For v*.local, the layout after Base64url decoding is: nonce, ciphertext, tag — concatenated. Lengths:
- v1.local: 32-byte nonce, ciphertext, 48-byte HMAC-SHA384 tag
- v2.local: 24-byte nonce, ciphertext, 16-byte Poly1305 tag
- v3.local: 32-byte nonce, ciphertext, 48-byte HMAC-SHA384 tag
- v4.local: 32-byte nonce, ciphertext, 32-byte BLAKE2b tag
The ciphertext is exactly the length of the plaintext JSON — no padding.
Footer segment:
If present, the footer is just Base64url-encoded raw bytes. PASETO doesn't impose any structure — your application defines it. By convention, JSON footers are common.
Pre-authentication encoding (PAE):
This is the magic glue that prevents bytes from being moved between segments. PAE concatenates the count of items, then for each item its little-endian length followed by its bytes. The signature/tag is computed over PAE(header, body, footer) (and implicit assertions in v3/v4). Tampering with any segment changes PAE and breaks verification.
Use Case
A developer building a custom PASETO library uses this anatomy to write a parser that correctly slices the trailing 64-byte signature off a v4.public payload before handing the JSON to the application.