PASETO Usage Examples

The following is a simple sample code using PySETO:

>>> import pyseto
>>> from pyseto import Key
>>> private_key_pem = b"-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEILTL+0PfTOIQcn2VPkpxMwf6Gbt9n4UEFDjZ4RuUKjd0\n-----END PRIVATE KEY-----"
>>> public_key_pem = b"-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAHrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI=\n-----END PUBLIC KEY-----"
>>> private_key = Key.new(version=4, purpose="public", key=private_key_pem)
>>> token = pyseto.encode(
...     private_key,
...     b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
... )
>>> token
B'v4.public.eyJkYXRhIjogInRoaXMgaXMgYSBzaWduZWQgbWVzc2FnZSIsICJleHAiOiAiMjAyMi0wMS0wMVQwMDowMDowMCswMDowMCJ9l1YiKei2FESvHBSGPkn70eFO1hv3tXH0jph1IfZyEfgm3t1DjkYqD5r4aHWZm1eZs_3_bZ9pBQlZGp0DPSdzDg'
>>> public_key = Key.new(version=4, purpose="public", key=public_key_pem)
>>> decoded = pyseto.decode(public_key, token)
>>> decoded.payload
B'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'

This page shows various examples to use PySETO.

v4.public

Asymmetric Authentication (Public-Key Signatures) with Ed25519 (EdDSA over Curve25519).

You can create an Ed25519 key pair by using openssl as follows:

$ openssl genpkey -algorithm ed25519 -out private_key.pem
$ openssl pkey -in private_key.pem -pubout -out public_key.pem

Use the key pair to generate and consume v4.public PASETO tokens as follows:

import pyseto
from pyseto import Key

with open("./private_key.pem") as key_file:
    private_key = Key.new(4, "public", key_file.read())
token = pyseto.encode(
    private_key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
    implicit_assertion=b"xyz",  # Optional
)

with open("./public_key.pem") as key_file:
    public_key = Key.new(4, "public", key_file.read())
decoded = pyseto.decode(public_key, token, implicit_assertion=b"xyz")

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v4"
assert decoded.purpose == "public"

v4.local

Authenticated Encryption with XChaCha20 + BLAKE2b-MAC (Encrypt-then-MAC).

import pyseto
from pyseto import Key

key = Key.new(version=4, purpose="local", key=b"our-secret")
token = pyseto.encode(
    key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
    implicit_assertion=b"xyz",  # Optional
)

decoded = pyseto.decode(key, token, implicit_assertion=b"xyz")

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v4"
assert decoded.purpose == "local"

v3.public

Asymmetric Authentication (Public-Key Signatures) with ECDSA over NIST P-384, with SHA-384, using RFC 6979 deterministic k-values.

You can create an ECDSA over NIST P-384 key pair by using openssl as follows:

$ openssl ecparam -genkey -name secp384r1 -noout -out private_key.pem
$ openssl ec -in private_key.pem -pubout -out public_key.pem

Use the key pair to generate and consume v3.public PASETO tokens as follows:

import pyseto
from pyseto import Key

with open("./private_key.pem") as key_file:
    private_key = Key.new(3, "public", key_file.read())
token = pyseto.encode(
    private_key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
    implicit_assertion=b"xyz",  # Optional
)

with open("./public_key.pem") as key_file:
    public_key = Key.new(3, "public", key_file.read())
decoded = pyseto.decode(public_key, token, implicit_assertion=b"xyz")

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v3"
assert decoded.purpose == "public"

v3.local

Symmetric Authenticated Encryption with AES-256-CTR + HMAC-SHA384 (Encrypt-then-MAC).

import pyseto
from pyseto import Key

key = Key.new(version=3, purpose="local", key=b"our-secret")
token = pyseto.encode(
    key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
    implicit_assertion=b"xyz",  # Optional
)

decoded = pyseto.decode(key, token, implicit_assertion=b"xyz")

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v3"
assert decoded.purpose == "local"

v2.public

Asymmetric Authentication (Public-Key Signatures) with Ed25519.

Create an Ed25519 key pair by using openssl as follows:

$ openssl genpkey -algorithm ed25519 -out private_key.pem
$ openssl pkey -in private_key.pem -pubout -out public_key.pem

Use the key pair to generate and consume v2.public PASETO tokens as follows:

import pyseto
from pyseto import Key

with open("./private_key.pem") as key_file:
    private_key = Key.new(2, "public", key_file.read())
token = pyseto.encode(
    private_key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
)

with open("./public_key.pem") as key_file:
    public_key = Key.new(2, "public", key_file.read())
decoded = pyseto.decode(public_key, token)

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v2"
assert decoded.purpose == "public"

v2.local

Symmetric Authenticated Encryption with XChaCha20-Poly1305 (192-bit nonce, 256-bit key and 128-bit authentication tag).

In this case, you must use 32 byte key as follows:

import pyseto
from pyseto import Key
from secrets import token_bytes

key = Key.new(version=2, purpose="local", key=token_bytes(32))
token = pyseto.encode(
    key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
)

decoded = pyseto.decode(key, token)

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v2"
assert decoded.purpose == "local"

v1.public

Asymmetric Authentication (Public-Key Signatures) with RSASSA-PSS 2048-bit key, SHA384 hashing and MGF1+SHA384.

Create an RSA key pair by using openssl as follows:

$ openssl genrsa -out private_key.pem 2048
$ openssl rsa -in private_key.pem -outform PEM -pubout -out public_key.pem

Use the key pair to generate and consume v1.public PASETO tokens as follows:

import pyseto
from pyseto import Key

with open("./private_key.pem") as key_file:
    private_key = Key.new(1, "public", key_file.read())
token = pyseto.encode(
    private_key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
)

with open("./public_key.pem") as key_file:
    public_key = Key.new(1, "public", key_file.read())
decoded = pyseto.decode(public_key, token)

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v1"
assert decoded.purpose == "public"

v1.local

Symmetric Authenticated Encryption with AES-256-CTR + HMAC-SHA384 (Encrypt-then-MAC).

import pyseto
from pyseto import Key
from secrets import token_bytes

key = Key.new(version=1, purpose="local", key=b"our-secret")
token = pyseto.encode(
    key,
    payload=b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}',
    footer=b"This is a footer",  # Optional
)

decoded = pyseto.decode(key, token)

assert (
    decoded.payload
    == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}'
)
assert decoded.footer == b"This is a footer"
assert decoded.version == "v1"
assert decoded.purpose == "local"

Using Paseto class for handling registered claims

By using Paseto class, you can change the default value of exp (the expiration date ot tokens), whether to include an iat claim, and other settings.

Note that pyseto.encode() and pyseto.decode() are aliases to the encode() and decode() of the global “Paseto” class instance created with the default settings.

import json
import pyseto
from pyseto import Key, Paseto

private_key_pem = b"-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEILTL+0PfTOIQcn2VPkpxMwf6Gbt9n4UEFDjZ4RuUKjd0\n-----END PRIVATE KEY-----"
public_key_pem = b"-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAHrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI=\n-----END PUBLIC KEY-----"

private_key = Key.new(version=4, purpose="public", key=private_key_pem)
paseto = Paseto.new(
    exp=3600, include_iat=True
)  # Default values are exp=0(not specified) and including_iat=False
token = paseto.encode(
    private_key,
    {"data": "this is a signed message"},
    serializer=json,
)
public_key = Key.new(version=4, purpose="public", key=public_key_pem)
decoded = pyseto.decode(public_key, token, deserializer=json)

assert decoded.payload["data"] == "this is a signed message"
assert decoded.payload["iat"] == "2021-11-11T00:00:00+00:00"
assert decoded.payload["exp"] == "2021-11-11T01:00:00+00:00"