Skip to main content

rustauth_plugins/siwe/
mod.rs

1//! Sign-In with Ethereum plugin.
2
3mod address;
4mod endpoints;
5mod schema;
6mod store;
7mod types;
8
9use rustauth_core::error::RustAuthError;
10use rustauth_core::plugin::AuthPlugin;
11
12pub use address::{checksum_address, SiweAddressError};
13pub use schema::SiweSchemaOptions;
14pub use types::{
15    Cacao, CacaoHeader, CacaoPayload, CacaoSignature, EnsLookupArgs, EnsLookupResult, SiweOptions,
16    SiweOptionsBuilder, SiweVerifyMessageArgs, WalletAddress,
17};
18
19pub const UPSTREAM_PLUGIN_ID: &str = "siwe";
20
21/// Development only — do not use in production.
22///
23/// Uses domain `localhost`, an in-memory nonce counter, and accepts every SIWE signature.
24pub fn siwe_dev() -> Result<AuthPlugin, RustAuthError> {
25    siwe_dev_domain("localhost")
26}
27
28/// Development only — same as [`siwe_dev`] with an explicit domain.
29pub fn siwe_dev_domain(domain: impl Into<String>) -> Result<AuthPlugin, RustAuthError> {
30    use std::sync::atomic::{AtomicU64, Ordering};
31
32    static NONCE: AtomicU64 = AtomicU64::new(0);
33    siwe(SiweOptions::new(
34        domain,
35        || async {
36            let nonce = NONCE.fetch_add(1, Ordering::Relaxed);
37            Ok(format!("dev-nonce-{nonce}"))
38        },
39        |_args| async { Ok(true) },
40    ))
41}
42
43pub fn siwe(options: SiweOptions) -> Result<AuthPlugin, RustAuthError> {
44    options.validate()?;
45    Ok(AuthPlugin::new(UPSTREAM_PLUGIN_ID)
46        .with_version(crate::VERSION)
47        .with_options(options.metadata())
48        .with_schema(schema::wallet_address_schema(options.schema_options()))
49        .with_endpoint(endpoints::nonce_endpoint(options.clone()))
50        .with_endpoint(endpoints::verify_endpoint(options)))
51}