- Docs
- Api%2Freference%2Fwallets%2FConnectEoa
Sign in with a crypto wallet
Let a user sign in with a crypto wallet they already own — MetaMask, Rainbow, Ledger — as their identity here. One endpoint covers both first time and every time after. 1. `GET /auth/challenge` — get a one-off string to sign. 2. Ask their wallet to sign it with `personal_sign`. 3. Send the signature here. We recover the address from the signature, so nothing but the signature itself proves who they are. On a first connection we create their Dual wallet for them; afterwards we recognise the address and start a new session. Either way the response carries their wallet and a session. No sign-in needed — this is the sign-in.
Request Body
application/json
EOA connect payload — challenge, signature, and optional metadata.
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
curl -X POST "https://api.dual.network/wallets/connect/eoa" \ -H "Content-Type: application/json" \ -d '{ "auth": { "challenge": "<challenge returned by GET /auth/challenge>", "signature": "<0x-prefixed 65-byte signature>" }, "organization_id": "665f1c2d4b1a2c3d4e5f6aa0", "nickname": "alexf", "email": "alex@example.com", "language": "en" }'{
"wallet": {
"id": "665f1c2d4b1a2c3d4e5f6a01",
"fqdn": "dual.network",
"email": "alex@example.com",
"nickname": "alexf",
"language": "en",
"activated": true,
"disabled": false,
"account": {
"address": "0x1234567890abcdef1234567890abcdef12345678",
"type": "SMART_WALLET",
"controller": {
"address": "0x9876543210fedcba9876543210fedcba98765432",
"type": "SECP256K1",
"custody": "self-custodial"
},
"smart_account": {
"chain_id": 42161,
"factory": "0x7777777777777777777777777777777777777777",
"implementation": "0x8888888888888888888888888888888888888888",
"index": 0,
"validator": "0x9999999999999999999999999999999999999999",
"validator_type": "ECDSA",
"version": "0.3.1"
}
},
"when_created": "2026-02-01T09:00:00Z",
"when_modified": "2026-02-01T09:00:00Z"
},
"access_token": "<access token>",
"refresh_token": "<refresh token>"
}{
"code": 3,
"message": "Key: 'limit' Error:Field validation for 'limit' failed on the 'lte' tag"
}{
"code": 3,
"message": "limit must be 25 or less",
"details": {}
}{
"code": 13,
"message": "internal error"
}