### PySETO Interactive Example Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md An interactive Python console example showing basic PASETO token encoding and decoding with v4 public keys. ```python 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= -----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 public_key = Key.new(version=4, purpose="public", key=public_key_pem) decoded = pyseto.decode(public_key, token) decoded.payload ``` -------------------------------- ### Install PySETO Source: https://github.com/dajiaji/pyseto/blob/main/docs/index.md Install the PySETO library using pip. This command installs the latest version of the package. ```console pip install pyseto ``` -------------------------------- ### Run Tests with Tox Source: https://github.com/dajiaji/pyseto/blob/main/README.md Execute project tests using the tox testing framework. Ensure tox is installed in your environment. ```shell $ tox ``` -------------------------------- ### Password-based Key Encryption (secret-pw) Source: https://github.com/dajiaji/pyseto/blob/main/docs/paserk_usage.md Encrypts and decrypts a PASERK using a secret password, starting from an existing PASERK. The public key is used for decoding the final token. ```python import pyseto from pyseto import Key raw_private_key = Key.from_paserk( "k4.secret.tMv7Q99M4hByfZU-SnEzB_oZu32fhQQUONnhG5QqN3Qeudu7vAR8A_1wYE4AcfCYfhayi3VyJcEfAEFdDiCxog" ) wpk = raw_private_key.to_paserk(password="our-secret") unwrapped_private_key = Key.from_paserk(wpk, password="our-secret") token = pyseto.encode( unwrapped_private_key, b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}', ) public_key = Key.from_paserk("k4.public.Hrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI") decoded = pyseto.decode(public_key, token) # assert wpk == "k4.secret-pw.MEMW4K1MaD5nWigCLyEyFAAAAAAA8AAAAAAAAgAAAAFU-tArtryNVjS2n2hCYiM11V6tOyuIog69Bjb0yNZanrLJ3afGclb3kPzQ6IhK8ob9E4QgRdEALGWCizZ0RCPFF_M95IQDfmdYKC0Er656UgKUK4UKG9JlxP4o81UwoJoZYz_D1zTlltipEa5RiNvUtNU8vLKoGSY" assert ( decoded.payload == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) ``` -------------------------------- ### pyseto.Key.new Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Constructor of a PASETO key object which has KeyInterface. ```APIDOC ## pyseto.Key.new ### Description Constructor of a PASETO key object which has [`KeyInterface`](#pyseto.key_interface.KeyInterface). ### Method `pyseto.Key.new(version: int, purpose: str, key: bytes | str = b'') -> [KeyInterface](#pyseto.key_interface.KeyInterface)` ### Parameters #### Arguments - **version** (*int*) – The version of the key. It will be `1`, `2`, `3` or `4`. - **purpose** (*str*) – The purpose of the key. It will be `public` or `local`. - **key** (*Union* *[**bytes* *,* *str* *]*) – A key itself or keying material. ### Returns A PASETO key object. ### Return type [KeyInterface](#pyseto.KeyInterface) ### Raises **ValueError** – Invalid arguments. ``` -------------------------------- ### Generate RSA Keys for v1.public Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Shows how to generate RSA 2048-bit private and public key files using openssl, which are required for creating and verifying v1.public PASETO tokens. ```console $ openssl genrsa -out private_key.pem 2048 $ openssl rsa -in private_key.pem -outform PEM -pubout -out public_key.pem ``` -------------------------------- ### Basic PASETO v4.public Usage Source: https://github.com/dajiaji/pyseto/blob/main/README.md Demonstrates encoding and decoding a PASETO v4.public token using provided private and public keys. Ensure keys are correctly formatted PEM strings. ```python 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-----" # Create a PASETO token. 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"}', ) # Decode and verify a PASETO token. public_key = Key.new(version=4, purpose="public", key=public_key_pem) decoded = pyseto.decode(public_key, token) assert ( token == b"v4.public.eyJkYXRhIjogInRoaXMgaXMgYSBzaWduZWQgbWVzc2FnZSIsICJleHAiOiAiMjAyMi0wMS0wMVQwMDowMDowMCswMDowMCJ9l1YiKei2FESvHBSGPkn70eFO1hv3tXH0jph1IfZyEfgm3t1DjkYqD5r4aHWZm1eZs_3_bZ9pBQlZGp0DPSdzDg" ) assert ( decoded.payload == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) ``` -------------------------------- ### PySETO v4 Public Token Encode/Decode Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates encoding and decoding of v4 public PASETO tokens using Ed25519 keys. Requires private and public key files. ```python 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" ``` -------------------------------- ### PySETO v3 Public Token Encode/Decode Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates encoding and decoding of v3 public PASETO tokens using ECDSA over NIST P-384 keys. Requires private and public key files. ```python 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" ``` -------------------------------- ### PySETO v4 Local Token Encode/Decode Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates encoding and decoding of v4 local PASETO tokens using a shared secret key. ```python 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" ``` -------------------------------- ### Paseto.new Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Constructor for the Paseto processor. It allows setting default expiration times, including issued-at claims, and leeway for validation. ```APIDOC ## Paseto.new ### Description Constructor of PASETO processor. ### Method Signature `Paseto.new(exp: int = 0, include_iat: bool = False, leeway: int = 0) -> Paseto` ### Parameters * **exp** (*int*) - A default expiration time (seconds) of PASETO tokens. It will be set in the payload as the registered `exp` claim when calling `encode()` with serializer=`json` and this value > `0`. If the value <= `0`, the `exp` claim will not be set. In addition, this value can be overwritten by the `exp` parameter of `encode()`. The default value is `0`. * **include_iat** (*bool*) - If this value is `True`, PASETO tokens which are created through `encode()` include an `iat` claim when calling `encode()` with serializer=`json`. The default value is `False`. * **leeway** (*int*) - The leeway in seconds for validating `exp` and `nbf`. The default value is `0`. ### Returns A PASETO processor object. ### Return type Paseto ``` -------------------------------- ### Using Paseto Class for Registered Claims Source: https://github.com/dajiaji/pyseto/blob/main/README.md Configure default expiration (`exp`) and inclusion of issued-at (`iat`) claims when creating PASETO tokens. `pyseto.encode/decode` are aliases for the default `Paseto` instance. ```python 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= -----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" ``` -------------------------------- ### Generate Ed25519 Keys for v2.public Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Shows how to generate Ed25519 private and public key files using openssl, which are required for creating and verifying v2.public PASETO tokens. ```console $ openssl genpkey -algorithm ed25519 -out private_key.pem $ openssl pkey -in private_key.pem -pubout -out public_key.pem ``` -------------------------------- ### Serialize and Deserialize PASERK Keys Source: https://github.com/dajiaji/pyseto/blob/main/docs/paserk_usage.md Demonstrates generating pyseto.Key objects from PASERK strings and converting pyseto.Key objects back to PASERK format. This is useful for managing and exchanging keys. ```python import pyseto from pyseto import Key # pyseto.Key can be generated from PASERK. symmetric_key = Key.new(version=4, purpose="local", key=b"our-secret") private_key = Key.from_paserk( "k4.secret.tMv7Q99M4hByfZU-SnEzB_oZu32fhQQUONnhG5QqN3Qeudu7vAR8A_1wYE4AcfCYfhayi3VyJcEfAEFdDiCxog" ) public_key = Key.from_paserk("k4.public.Hrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI") token = pyseto.encode( private_key, b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}', ) decoded = pyseto.decode(public_key, token) assert ( decoded.payload == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) # PASERK can be derived from pyseto.Key. assert symmetric_key.to_paserk() == "k4.local.b3VyLXNlY3JldA" assert ( private_key.to_paserk() == "k4.secret.tMv7Q99M4hByfZU-SnEzB_oZu32fhQQUONnhG5QqN3Qeudu7vAR8A_1wYE4AcfCYfhayi3VyJcEfAEFdDiCxog" ) assert public_key.to_paserk() == "k4.public.Hrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI" ``` -------------------------------- ### Configure Paseto Instance for Claims Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Use the Paseto class to configure default values for registered claims like expiration time (`exp`) and whether to include the issued-at claim (`iat`). ```python 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" ``` -------------------------------- ### KeyInterface.from_asymmetric_key_params Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Constructs a PASETO key object using asymmetric key parameters (x, y, and private key). Useful for generating keys from JWK or similar formats. ```APIDOC ## static KeyInterface.from_asymmetric_key_params ### Description Constructor of a PASETO key object which has [`KeyInterface`](#pyseto.key_interface.KeyInterface) wth asymmetric key parameters (x-coordinate, y-coordinate, and/or private key). This is intended to be used to generate keys for PASETO from JWK and other sources. ### Parameters #### Path Parameters * **version** (int) - Required - The version of the key. It will be `1`, `2`, `3` or `4`. * **x** (bytes) - Optional - The x coordinate of the key. * **y** (bytes) - Optional - The y coordinate of the key. * **d** (bytes) - Optional - The private key component of the key. ### Returns A PASETO key object. ### Return type [KeyInterface](#pyseto.key_interface.KeyInterface) ### Raises **ValueError** – Invalid arguments. ``` -------------------------------- ### Password-based Key Encryption Source: https://github.com/dajiaji/pyseto/blob/main/README.md Shows how to encrypt a pyseto.Key using a password, creating a password-protected PASERK. This encrypted key can be decrypted using the same password. ```python import pyseto from pyseto import Key raw_key = Key.new(version=4, purpose="local", key=b"our-secret") token = pyseto.encode( raw_key, b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) wpk = raw_key.to_paserk(password="our-secret") unwrapped_key = Key.from_paserk(wpk, password="our-secret") decoded = pyseto.decode(unwrapped_key, token) ``` -------------------------------- ### Key Wrapping with local-wrap.pie Source: https://github.com/dajiaji/pyseto/blob/main/docs/paserk_usage.md Encrypts a PASERK using a symmetric wrapping key, creating a 'local-wrap.pie' format. The wrapped key can be decrypted using the same wrapping key. ```python import pyseto from pyseto import Key raw_key = Key.new(version=4, purpose="local", key=b"our-secret") wrapping_key = token_bytes(32) wpk = raw_key.to_paserk(wrapping_key=wrapping_key) token = pyseto.encode( raw_key, b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) unwrapped_key = Key.from_paserk(wpk, wrapping_key=wrapping_key) decoded = pyseto.decode(unwrapped_key, token) # assert wpk == "k4.local-wrap.pie.TNKEwC4K1xBcgJ_GiwWAoRlQFE33HJO3oN9DHEZ05pieSCd-W7bgAL64VG9TZ_pBkuNBFHNrfOGHtnfnhYGdbz5-x3CxShhPJxg" assert ( decoded.payload == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) ``` -------------------------------- ### KeyInterface.to_paserk Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Serializes the key into a PASERK string. Supports wrapping the key with a symmetric key or a password, with options for iteration, memory, time cost, and parallelism for password-based wrapping. ```APIDOC ## KeyInterface.to_paserk ### Description Returns the PASERK expression of the key. ### Parameters #### Path Parameters * **wrapping_key** (bytes | str) - Optional - A wrapping key to wrap the key. If the wrapping_key is specified, password should not be specified. * **password** (bytes | str) - Optional - A password to wrap the key. If the password is specified, wrapping_key should not be specified. * **sealing_key** (bytes | str) - Optional - A sealing key to seal the key. * **iteration** (int) - Optional - An iteration count used for password-based key wrapping. This argument will only be used when the password is specified. * **memory_cost** (int) - Optional - Amount of memory to use for password-based key wrapping using argon2. This argument will only be used when the password is specified for v2/v4 key. * **time_cost** (int) - Optional - Number of iterations to perform for password-based key wrapping using argon2. This argument will only be used when the password is specified for v2/v4 key. * **parallelism** (int) - Optional - Degree of parallelism for password-based key wrapping using argon2. This argument will only be used when the password is specified for v2/v4 key. ### Returns A PASERK string. ### Return type str ### Raises **ValueError** – Invalid arguments. **EncryptError** – Failed to wrap the key. ``` -------------------------------- ### Encode and Decode v1.local PASETO Token Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates symmetric authenticated encryption using AES-256-CTR + HMAC-SHA384 for v1.local PASETO tokens. Requires a secret key for both encoding and decoding. ```python 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" ``` -------------------------------- ### Encode and Decode v3.local PASETO Token Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates symmetric authenticated encryption using AES-256-CTR + HMAC-SHA384 for v3.local PASETO tokens. Requires a secret key for both encoding and decoding. ```python 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" ``` -------------------------------- ### KeyInterface.to_paserk Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Converts the key into its PASERK expression, optionally wrapping it with a key or password. ```APIDOC ## KeyInterface.to_paserk() ### Description Returns the PASERK expression of the key. ### Method `to_paserk(wrapping_key: bytes | str = b'', password: bytes | str = b'', sealing_key: bytes | str = b'', iteration: int = 100000, memory_cost: int = 15360, time_cost: int = 2, parallelism: int = 1) -> str` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **wrapping_key** (bytes | str) - Optional - A wrapping key to wrap the key. If the wrapping_key is specified, password should not be specified. - **password** (bytes | str) - Optional - A password to wrap the key. If the password is specified, wrapping_key should not be specified. - **sealing_key** (bytes | str) - Optional - A sealing key. - **iteration** (int) - Optional - An iteration count used for password-based key wrapping. This argument will only be used when the password is specified. - **memory_cost** (int) - Optional - Amount of memory to use for password-based key wrapping using argon2. This argument will only be used when the password is specified for v2/v4 key. - **time_cost** (int) - Optional - Number of iterations to perform for password-based key wrapping using argon2. This argument will only be used when the password is specified for v2/v4 key. - **parallelism** (int) - Optional - Degree of parallelism for password-based key wrapping using argon2. This argument will only be used when the password is specified for v2/v4 key. ### Returns - **str**: A PASERK string. ### Raises - **ValueError**: Invalid arguments. - **EncryptError**: Failed to wrap the key. ``` -------------------------------- ### Encode and Decode v2.public PASETO Token Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates asymmetric authentication using Ed25519 signatures for v2.public PASETO tokens. Requires a private key for encoding and a public key for decoding. ```python 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" ``` -------------------------------- ### PASETO with JSON Serializer for Payload and Footer Source: https://github.com/dajiaji/pyseto/blob/main/README.md Encode/decode dict-typed payloads and footers as JSON. The `exp` parameter can set the token's expiration time in seconds. ```python import json 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= -----END PUBLIC KEY-----" private_key = Key.new(version=4, purpose="public", key=private_key_pem) public_key = Key.new(version=4, purpose="public", key=public_key_pem) token = pyseto.encode( private_key, {"data": "this is a signed message"}, footer={"kid": public_key.to_paserk_id()}, serializer=json, exp=3600, ) decoded = pyseto.decode(public_key, token, deserializer=json) assert decoded.payload["data"] == "this is a signed message" assert decoded.payload["exp"] == "2021-11-11T00:00:00+00:00" assert decoded.footer["kid"] == "k4.pid.yh4-bJYjOYAG6CWy0zsfPmpKylxS7uAWrxqVmBN2KAiJ" ``` -------------------------------- ### Encode and Decode v1.public PASETO Token Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates asymmetric authentication using RSASSA-PSS signatures for v1.public PASETO tokens. Requires a private key for encoding and a public key for decoding. ```python 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" ``` -------------------------------- ### Password-based Key Encryption (local-pw) Source: https://github.com/dajiaji/pyseto/blob/main/docs/paserk_usage.md Encrypts and decrypts a PASERK using a local password. Ensure the Key object is created with the correct version and purpose. ```python import pyseto from pyseto import Key raw_key = Key.new(version=4, purpose="local", key=b"our-secret") token = pyseto.encode( raw_key, b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) wpk = raw_key.to_paserk(password="our-secret") unwrapped_key = Key.from_paserk(wpk, password="our-secret") decoded = pyseto.decode(unwrapped_key, token) # assert wpk == "k4.local-pw.HrCs9Pu-2LB0l7jkHB-x2gAAAAAA8AAAAAAAAgAAAAGttW0IHZjQCHJdg-Vc3tqO_GSLR4vzLl-yrKk2I-l8YHj6jWpC0lQB2Z7uzTtVyV1rd_EZQPzHdw5VOtyucP0FkCU" assert ( decoded.payload == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) ``` -------------------------------- ### KeyInterface.from_paserk Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Generates a PASETO key object from a PASERK string. Supports wrapping keys or passwords for decryption. ```APIDOC ## classmethod KeyInterface.from_paserk ### Description Generates a PASETO key object which has [`KeyInterface`](#pyseto.key_interface.KeyInterface) from PASERK. ### Parameters #### Path Parameters * **paserk** (str) - Required - A PASERK string. * **wrapping_key** (bytes | str) - Optional - A wrapping key. If the wrapping_key is specified, password should not be specified. * **password** (bytes | str) - Optional - A password for key wrapping. If the password is specified, wrapping_key should not be specified. * **unsealing_key** (bytes | str) - Optional - A password for key wrapping. If the password is specified, wrapping_key should not be specified. ### Returns A PASETO key object. ### Return type [KeyInterface](#pyseto.key_interface.KeyInterface) ### Raises **ValueError** – Invalid arguments. ``` -------------------------------- ### Token Class Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Represents a parsed PASETO token object, returned by pyseto.decode. ```APIDOC ## class pyseto.token.Token ### Description The parsed token object which is a return value of [`pyseto.decode`](#pyseto.decode). ### Class Methods #### classmethod new(token: bytes | str) -> Token ### Properties #### property version: str The version of the token. It will be "v1", "v2", "v3" or "v4". #### property purpose: str The purpose of the token. It will be "local" or "public". #### property header: bytes The header of the token. It will be "..". For example, "v1.local.". #### property payload: bytes | dict[str, Any] The payload of the token which is a decoded binary string. It’s not Base64 encoded data. #### property footer: bytes | dict[str, Any] The footer of the token which is a decoded binary string. It’s not Base64 encoded data. ``` -------------------------------- ### Encode and Decode v2.local PASETO Token Source: https://github.com/dajiaji/pyseto/blob/main/docs/paseto_usage.md Demonstrates symmetric authenticated encryption using XChaCha20-Poly1305 for v2.local PASETO tokens. Requires a 32-byte secret key for both encoding and decoding. ```python 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" ``` -------------------------------- ### pyseto.decode Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Decodes a PASETO token with a key for decryption and/or verifying. ```APIDOC ## pyseto.decode ### Description Decodes a PASETO token with a key for decryption and/or verifying. ### Method `pyseto.decode(keys: [KeyInterface](#pyseto.key_interface.KeyInterface) | list[[KeyInterface](#pyseto.key_interface.KeyInterface)], token: bytes | str, implicit_assertion: bytes | str = b'', deserializer: Any | None = None, aud: str = '') -> [Token](#pyseto.token.Token)` ### Parameters #### Arguments - **keys** ([*KeyInterface*](#pyseto.key_interface.KeyInterface)) – A key for decryption or verifying the signature in the token. - **token** (*Union* *[**bytes* *,* *str* *]*) – A PASETO token to be decrypted or verified. - **implicit_assertion** (*Union* *[**bytes* *,* *str* *]*) – An implicit assertion. It is only used in `v3` or `v4`. - **deserializer** (*Optional* *[**Any* *]*) – A deserializer which is used when you want to deserialize a `payload` attribute in the response object. It must have a `loads()` function to deserialize the payload. Typically, you can use `json` or `cbor2`. - **aud** (*str*) – An audience claim value for the token verification. If `deserializer=json` and the payload of the token does not include an `aud` value that matches this value, the verification will fail. ### Returns A parsed PASETO token object. ### Return type [Token](#pyseto.Token) ### Raises - **ValueError** – Invalid arguments. - [**DecryptError**](#pyseto.DecryptError) – Failed to decrypt the message. - [**VerifyError**](#pyseto.VerifyError) – Failed to verify the message. ``` -------------------------------- ### Encode and Decode with v4 Public Keys Source: https://github.com/dajiaji/pyseto/blob/main/docs/index.md Use this snippet to encode a message into a v4 public token using a private key and then decode it using the corresponding public key. Ensure you have the correct PEM-formatted keys. ```python >>> import pyseto >>> from pyseto import Key >>> secret_key_pem = b"-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEILTL+0PfTOIQcn2VPkpxMwf6Gbt9n4UEFDjZ4RuUKjd0\n-----END PRIVATE KEY-----" >>> public_key_pem = b"-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAHrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI= -----END PUBLIC KEY-----" >>> secret_key = Key.new(version=4, purpose="public", key=secret_key_pem) >>> token = pyseto.encode( ... secret_key, ... '{"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(4, "public", 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"}' ``` -------------------------------- ### Serialize PASERK ID from pyseto.Key Source: https://github.com/dajiaji/pyseto/blob/main/docs/paserk_usage.md Shows how to derive PASERK IDs from pyseto.Key objects. PASERK IDs are used to identify keys without exposing their secret material. ```python import pyseto from pyseto import Key # pyseto.Key can be generated from PASERK. symmetric_key = Key.new(version=4, purpose="local", key=b"our-secret") private_key = Key.from_paserk( "k4.secret.tMv7Q99M4hByfZU-SnEzB_oZu32fhQQUONnhG5QqN3Qeudu7vAR8A_1wYE4AcfCYfhayi3VyJcEfAEFdDiCxog" ) public_key = Key.from_paserk("k4.public.Hrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI") # PASERK ID can be derived from pyseto.Key. assert ( symmetric_key.to_paserk_id() == "k4.lid._D6kgTzxgiPGk35gMj9bukgj4En2H94u22wVX9zaoh05" ) assert ( private_key.to_paserk() == "k4.secret.tMv7Q99M4hByfZU-SnEzB_oZu32fhQQUONnhG5QqN3Qeudu7vAR8A_1wYE4AcfCYfhayi3VyJcEfAEFdDiCxog" ) assert ( public_key.to_paserk_id() == "k4.pid.yh4-bJYjOYAG6CWy0zsfPmpKylxS7uAWrxqVmBN2KAiJ" ) ``` -------------------------------- ### KeyInterface Properties Source: https://github.com/dajiaji/pyseto/blob/main/docs/api.md Properties of the KeyInterface class that provide information about the key. ```APIDOC ## KeyInterface Properties ### version - **Type**: int - **Description**: The version of the key. It will be `1`, `2`, `3` or `4`. ### purpose - **Type**: str - **Description**: The purpose of the key. It will be `"local"` or `"public"`. ### header - **Type**: bytes - **Description**: The header value for a PASETO token. It will be `"v.."`. For example, `"v1.local."`. ### is_secret - **Type**: bool - **Description**: If it is True, the key is a symmetric key or an asymmetric secret key. ``` -------------------------------- ### Key Wrapping with secret-wrap.pie Source: https://github.com/dajiaji/pyseto/blob/main/docs/paserk_usage.md Encrypts a secret PASERK using a symmetric wrapping key, creating a 'secret-wrap.pie' format. This is useful for securely storing or transmitting private keys. ```python import pyseto from pyseto import Key raw_private_key = Key.from_paserk( "k4.secret.tMv7Q99M4hByfZU-SnEzB_oZu32fhQQUONnhG5QqN3Qeudu7vAR8A_1wYE4AcfCYfhayi3VyJcEfAEFdDiCxog" ) wrapping_key = token_bytes(32) wpk = raw_private_key.to_paserk(wrapping_key=wrapping_key) unwrapped_private_key = Key.from_paserk(wpk, wrapping_key=wrapping_key) token = pyseto.encode( unwrapped_private_key, b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}', ) public_key = Key.from_paserk("k4.public.Hrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI") decoded = pyseto.decode(public_key, token) # assert wpk == "k4.secret-wrap.pie.excv7V4-NaECy5hpji-tkSkMvyjsAgNxA-mGALgdjyvGNyDlTb89bJ35R1e3tILgbMpEW5WXMXzySe2T-sBz-ZAcs1j7rbD3ZWvsBTM6K5N9wWfAxbR4ppCXH_H5__9yY-kBaF2NimyAJyduhOhSmqLm6TTSucpAOakEJOXePW8" assert ( decoded.payload == b'{"data": "this is a signed message", "exp": "2022-01-01T00:00:00+00:00"}' ) ```