Skip to main content

A Python implementation of Sign in with Ethereum (EIP-4361).

Project description

Sign in with Ethereum

This package provides a Python implementation of EIP-4361: Sign in with Ethereum.

Installation

SIWE can be easily installed in any Python project with pip:

pip install signinwithethereum

The distribution is published as signinwithethereum; the import name is siwe:

from siwe import SiweMessage

Usage

SIWE provides a SiweMessage class which implements EIP-4361.

Parsing a SIWE Message

Parsing is done by initializing a SiweMessage object with an EIP-4361 formatted string:

from siwe import SiweMessage
message = SiweMessage.from_message(message=eip_4361_string)

Or to initialize a SiweMessage as a pydantic.BaseModel right away:

message = SiweMessage(domain="login.xyz", address="0x1234...", ...)

Verifying and Authenticating a SIWE Message

Verification and authentication is performed via EIP-191, using the address field of the SiweMessage as the expected signer. The verify method checks message structural integrity, signature address validity, and time-based validity attributes.

Replay protection relies on a single-use nonce that your server issues, stores alongside the pending session, passes to verify, and consumes on success. Always pass the nonce you issued — a signature verified without a nonce check can be replayed.

try:
    message.verify(
        signature="0x...",
        domain="example.com",
        nonce=expected_nonce,  # the nonce your server issued for this session
        uri="https://example.com/login",
        chain_id=1,
        strict=True,
    )
    # Consume the nonce now so it cannot be replayed.
except siwe.VerificationError:
    # Invalid

Passing strict=True enforces that domain, uri, chain_id, and nonce are all supplied. Prefer it for authentication flows.

Smart-contract wallet signatures (EIP-1271 / EIP-6492)

For signatures produced by contract wallets (Safe, Argent, etc.) rather than externally owned accounts, pass a web3 provider to verify. The authentication arguments (strict, domain, nonce, uri, chain_id) still apply — the provider only changes how the signature itself is verified:

from web3 import HTTPProvider

message.verify(
    signature="0x...",
    domain="example.com",
    nonce=expected_nonce,
    uri="https://example.com/login",
    chain_id=1,
    strict=True,
    provider=HTTPProvider("https://mainnet.infura.io/v3/..."),
)

EOA recovery is tried first; if it fails, the signature is checked on-chain via isValidSignature(bytes32,bytes) per EIP-1271. Signatures carrying the EIP-6492 magic suffix are handed to the universal off-chain validator bytecode via eth_call, which covers counterfactual (undeployed) wallets as well as already-deployed ones. The provider's chain id is checked against the message's chain_id before any on-chain call.

Note: this is verification only. EIP-6492 allows a verifier to optionally submit the factory transaction after a successful check to finalize on-chain deployment ("side-effectful" verification). This library does not do that — if you need the wallet actually deployed, submit the factory call yourself.

Serialization of a SIWE Message

SiweMessage instances can also be serialized as their EIP-4361 string representations via the prepare_message method:

print(message.prepare_message())

Example

Parsing and verifying a SiweMessage is easy:

try:
    message = SiweMessage.from_message(eip_4361_string)
    message.verify(
        signature,
        domain="example.com",
        nonce=expected_nonce,
        uri="https://example.com/login",
        chain_id=1,
        strict=True,
    )
except ValueError:
    # Invalid message format
    print("Authentication attempt rejected.")
except siwe.ExpiredMessage:
    print("Authentication attempt rejected.")
except siwe.DomainMismatch:
    print("Authentication attempt rejected.")
except siwe.NonceMismatch:
    print("Authentication attempt rejected.")
except siwe.InvalidSignature:
    print("Authentication attempt rejected.")

# Message has been verified. Invalidate the stored nonce, then continue with authorization/other.

Testing

git submodule update --init
uv sync
uv run pytest

See Also

Disclaimer

Our Python library for Sign in with Ethereum has not yet undergone a formal security audit. We welcome continued feedback on the usability, architecture, and security of this implementation.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

signinwithethereum-5.0.1.tar.gz (166.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

signinwithethereum-5.0.1-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

File details

Details for the file signinwithethereum-5.0.1.tar.gz.

File metadata

  • Download URL: signinwithethereum-5.0.1.tar.gz
  • Upload date:
  • Size: 166.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for signinwithethereum-5.0.1.tar.gz
Algorithm Hash digest
SHA256 9661ac2020cb659cc7c3fc1f9b8a9ff59f2018e259f7a4e1ae641f126a475fa3
MD5 128af5bf6d2fec9f6a46cb85fef4d936
BLAKE2b-256 c69c5bca1085418726e08c333b4b97891c2d03f12b99973418acf7357dd76a54

See more details on using hashes here.

Provenance

The following attestation bundles were made for signinwithethereum-5.0.1.tar.gz:

Publisher: publish.yml on signinwithethereum/siwe-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file signinwithethereum-5.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for signinwithethereum-5.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 53551a1073209f4f011589a957efb8603650af7be24433f966bf897405c0ebd3
MD5 1c76e69b2b76542a06050ee93d15a599
BLAKE2b-256 8322ac218e503a9634757c09ab66e50a6dc3c9bfaaa877163a744516d33c85ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for signinwithethereum-5.0.1-py3-none-any.whl:

Publisher: publish.yml on signinwithethereum/siwe-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page