Sign-In With Tenzro
Authenticate a Tenzro identity to any website or API with an EIP-4361-shaped message signed by a hardware-rooted key.
Sign-In With Tenzro (SIWT) lets a website, API or agent authenticate a Tenzro identity. The user signs a short, human-readable message scoped to the requesting domain, and the relying party checks the signature against the identity's registered keys. The message format follows EIP-4361 (Sign-In with Ethereum) byte for byte, so existing SIWE parsers can read it.
The signature comes from a hardware-rooted key: a passkey with user verification for a person, a TPM 2.0 or Secure Enclave key for a machine. Like every Tenzro signature it is hybrid (classical plus ML-DSA-65). See Hardware-rooted keys.
The message
example.com wants you to sign in with your Tenzro account:
0x1234567890abcdef1234567890abcdef12345678
Sign in to Example
URI: https://example.com/login
Version: 1
Chain ID: <Tenzro Network chain id>
Nonce: abc123XYZ
Issued At: 2026-10-01T12:00:00Z
Expiration Time: 2026-10-01T12:05:00Z
Request ID: req-001
Resources:
- https://example.com/r1| Field | Notes |
|---|---|
| Domain | The host asking for the sign-in. Wallets should show it to the user and refuse one that does not match the page's origin. |
| Address | The Tenzro account. The EVM-shaped 20-byte form is accepted, as EIP-4361 requires. |
| Statement | Optional text shown to the user. |
| URI | The resource being signed in to. A tenzro:// URI is allowed. |
| Version | 1. |
| Chain ID | The value eth_chainId returns on Tenzro Network. |
| Nonce | At least eight random alphanumeric characters, issued by the relying party. |
| Issued At, Expiration Time, Not Before | RFC 3339 timestamps. |
| Request ID, Resources | Optional. |
Always read the chain id from the network (eth_chainId) rather than hard-coding it.
Flow
- Issue a nonce. The relying party generates a random nonce and stores it against the pending sign-in.
- Build the message. Fill in the fields and render the canonical text locally.
- Sign. The user's wallet shows the domain and statement and signs the exact canonical bytes with their hardware-rooted key.
- Verify. The relying party parses the message, checks the domain, nonce and time window, resolves the DID document for the address (
tenzro_resolveDidDocument), and verifies the hybrid signature against the verification methods it lists. - Consume the nonce. Mark it used so the same signed message cannot be replayed.
Verification is stateless on the network side: replay protection comes from the relying party's nonce store.
Build the message
The message is plain text in a fixed layout, built and parsed on the client; no call to a node is needed. Read the chain id first:
CHAIN_ID=$(printf '%d' "$(curl -s https://rpc.tenzro.com \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}' | jq -r .result)")Then render the fields in order, one per line, exactly as the table above names them, and have the wallet sign those exact bytes. A parser must refuse a message that is missing a required field such as URI.
Checking the time window
A verifier rejects a message whose Expiration Time has passed or whose Not Before is still in the future. Keep expiry short, a few minutes, and issue a fresh nonce for every attempt.
Related
- Identity: resolving the DID behind an address
- Console and passkey wallet
- RPC access: how signed requests authorise owner methods