X402.Extensions.SIWX (X402 v0.3.3)

Copy Markdown View Source

Encodes and decodes SIWX messages and SIGN-IN-WITH-X header values.

SIWX messages follow the SIWE (EIP-4361) textual format and use CAIP-2 chain identifiers for EVM networks (eip155:*).

Summary

Header Encoding

Decodes a SIWX SIGN-IN-WITH-X header.

Encodes a SIWX header payload with message and signature fields.

Returns the canonical SIWX header name.

Functions

Decodes an EIP-4361 SIWX message into payload fields.

Encodes a SIWX payload into an EIP-4361 message.

Header Encoding

decode_header(value)

(since 0.3.0)
@spec decode_header(String.t()) :: {:ok, map()} | {:error, header_decode_error()}

Decodes a SIWX SIGN-IN-WITH-X header.

Examples

iex> {:ok, encoded} = X402.Extensions.SIWX.encode_header(%{message: "hello", signature: "0xabc"})
iex> X402.Extensions.SIWX.decode_header(encoded)
{:ok, %{"message" => "hello", "signature" => "0xabc"}}

iex> X402.Extensions.SIWX.decode_header("%%")
{:error, :invalid_base64}

encode_header(payload)

(since 0.3.0)
@spec encode_header(map()) :: {:ok, String.t()} | {:error, header_encode_error()}

Encodes a SIWX header payload with message and signature fields.

Examples

iex> {:ok, header} = X402.Extensions.SIWX.encode_header(%{message: "hello", signature: "0xabc"})
iex> {:ok, decoded} = X402.Extensions.SIWX.decode_header(header)
iex> decoded["message"]
"hello"

header_name()

(since 0.3.0)
@spec header_name() :: String.t()

Returns the canonical SIWX header name.

Examples

iex> X402.Extensions.SIWX.header_name()
"SIGN-IN-WITH-X"

Types

decode_error()

@type decode_error() :: :invalid_message | {:invalid_field, atom()}

encode_error()

@type encode_error() ::
  :invalid_payload | {:missing_fields, [atom()]} | {:invalid_field, atom()}

header_decode_error()

@type header_decode_error() :: :invalid_base64 | :invalid_json | :invalid_payload

header_encode_error()

@type header_encode_error() :: :invalid_payload | :invalid_json

message_payload()

@type message_payload() :: %{
  domain: String.t(),
  address: String.t(),
  statement: String.t(),
  uri: String.t(),
  version: String.t(),
  chain_id: String.t(),
  nonce: String.t(),
  issued_at: String.t(),
  expiration_time: String.t()
}

SIWX message payload fields.

Functions

decode(message)

(since 0.3.0)
@spec decode(String.t()) :: {:ok, message_payload()} | {:error, decode_error()}

Decodes an EIP-4361 SIWX message into payload fields.

Examples

iex> payload = %{
...>   domain: "example.com",
...>   address: "0x1111111111111111111111111111111111111111",
...>   statement: "Access purchased content",
...>   uri: "https://example.com/protected",
...>   version: "1",
...>   chain_id: "eip155:1",
...>   nonce: "abc12345",
...>   issued_at: "2026-02-16T12:00:00Z",
...>   expiration_time: "2026-02-16T13:00:00Z"
...> }
iex> {:ok, message} = X402.Extensions.SIWX.encode(payload)
iex> X402.Extensions.SIWX.decode(message)
{:ok, payload}

encode(payload)

(since 0.3.0)
@spec encode(map()) :: {:ok, String.t()} | {:error, encode_error()}

Encodes a SIWX payload into an EIP-4361 message.

:chain_id accepts either "eip155:<id>" or a positive integer.

Examples

iex> payload = %{
...>   domain: "example.com",
...>   address: "0x1111111111111111111111111111111111111111",
...>   statement: "Access purchased content",
...>   uri: "https://example.com/protected",
...>   version: "1",
...>   chain_id: "eip155:1",
...>   nonce: "abc12345",
...>   issued_at: "2026-02-16T12:00:00Z",
...>   expiration_time: "2026-02-16T13:00:00Z"
...> }
iex> {:ok, message} = X402.Extensions.SIWX.encode(payload)
iex> is_binary(message)
true