Skip to main content

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.

Metadata

Release files for signinwithethereum 5.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for signinwithethereum 5.0.2
File Size Uploaded
signinwithethereum-5.0.2.tar.gz 166.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for signinwithethereum 5.0.2
File Interpreter ABI Platform
signinwithethereum-5.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 184.8 kB

Release files / signinwithethereum-5.0.2.tar.gz

Download URL signinwithethereum-5.0.2.tar.gz
Size 166.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ddce654b4b89faea48720411df20d84839b246f59825716728ae79b30bd973b1
BLAKE2b-256 checksum
How to use checksums
34e576c345318881118e6f4f08e1097445aaac1124c62f2cc5fb2d97de12db36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / signinwithethereum-5.0.2-py3-none-any.whl

Download URL signinwithethereum-5.0.2-py3-none-any.whl
Size 18.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3241c75f6c1ee61bc4184175ee5f8a5ac8cac7d6d10c3291e6cd18974d5adb44
BLAKE2b-256 checksum
How to use checksums
74a836d213f23c3540f777364cad5eccbbac181281d8e9d6a7da09552c5590dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

5.0.2 This release

2 release files

5.0.1

2 release files

5.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page