Skip to content

Commit 36cd6ca

Browse files
tusharshah21joelamouche
authored andcommitted
docs: Add comprehensive SIWE nonce authentication documentation
1 parent c5b9c19 commit 36cd6ca

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed

docs/SIWE_NONCE_AUTHENTICATION.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# SIWE Nonce Authentication Implementation
2+
3+
## Overview
4+
5+
This document describes the implementation of dynamic nonce-based authentication for Sign-In with Ethereum (SIWE) to prevent replay attacks.
6+
7+
## What is SIWE?
8+
9+
Sign-In with Ethereum (SIWE) is an authentication standard that allows users to authenticate with applications using their Ethereum wallet. Users sign a standardized message with their private key, proving ownership of their wallet address.
10+
11+
## The Problem: Replay Attacks
12+
13+
Without nonce protection, a malicious actor could:
14+
1. Capture a user's signed SIWE message
15+
2. Reuse that signature to authenticate as the user
16+
3. Perform unauthorized actions on behalf of the user
17+
18+
## The Solution: Dynamic Nonces
19+
20+
Each authentication request includes a unique nonce that:
21+
- Starts at `1` for new users
22+
- Increments after each successful authentication
23+
- Is unique per wallet address
24+
- Prevents signature reuse
25+
26+
## Implementation Details
27+
28+
### Database Schema
29+
30+
```sql
31+
-- Migration: 003_add_nonces.sql
32+
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS login_nonce BIGINT NOT NULL DEFAULT 1;
33+
```
34+
35+
### API Endpoints
36+
37+
#### Get Nonce
38+
```
39+
GET /auth/nonce/:wallet_address
40+
```
41+
42+
Returns the current nonce for a wallet address:
43+
```json
44+
{
45+
"nonce": 1,
46+
"address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
47+
}
48+
```
49+
50+
### Authentication Flow
51+
52+
1. **Frontend requests nonce** from `/auth/nonce/:address`
53+
2. **Backend returns current nonce** (starts at 1 for new users)
54+
3. **Frontend generates SIWE message**:
55+
```
56+
Sign this message to authenticate with The Guild.
57+
58+
Nonce: 1
59+
```
60+
4. **User signs message** with MetaMask
61+
5. **Frontend sends signature** to protected endpoint
62+
6. **Backend verifies signature** against reconstructed message
63+
7. **Backend increments nonce** for next authentication
64+
65+
### Security Benefits
66+
67+
- **Replay Attack Prevention**: Each nonce can only be used once
68+
- **User Isolation**: Each wallet has independent nonce sequence
69+
- **Fresh Authentication**: No cached nonces - always current
70+
- **Cryptographic Security**: Uses ethers.js for proper signature verification
71+
72+
### Code Structure
73+
74+
#### Backend
75+
- `src/domain/repositories/profile_repository.rs` - Repository interface
76+
- `src/infrastructure/repositories/postgres_profile_repository.rs` - PostgreSQL implementation
77+
- `src/application/queries/get_login_nonce.rs` - Application query
78+
- `src/presentation/handlers.rs` - API handler
79+
- `src/infrastructure/services/ethereum_address_verification_service.rs` - Signature verification
80+
81+
#### Frontend
82+
- `src/hooks/profiles/use-get-nonce.ts` - Nonce fetching hook
83+
- `src/lib/utils/siwe.ts` - SIWE message generation
84+
- `src/components/profiles/action-buttons/` - Updated UI components
85+
86+
### Usage Examples
87+
88+
#### Creating a Profile
89+
```typescript
90+
// 1. Fetch nonce
91+
const { data: nonceData } = useGetNonce(walletAddress);
92+
93+
// 2. Generate SIWE message
94+
const message = generateSiweMessage(nonceData.nonce);
95+
96+
// 3. Sign with wallet
97+
const signature = await signMessageAsync({ message });
98+
99+
// 4. Create profile
100+
await createProfile.mutateAsync({
101+
input: { name: "John Doe", description: "Developer" },
102+
signature
103+
});
104+
```
105+
106+
#### Backend Verification
107+
```rust
108+
// Reconstruct expected message
109+
let expected_message = format!(
110+
"Sign this message to authenticate with The Guild.\n\nNonce: {}",
111+
nonce
112+
);
113+
114+
// Verify signature
115+
let recovered_address = signature.recover(expected_message)?;
116+
117+
// Increment nonce after successful verification
118+
profile_repository.increment_login_nonce(&wallet_address).await?;
119+
```
120+
121+
### Testing
122+
123+
#### Manual Testing
124+
1. Start backend: `cargo run --bin guild-backend`
125+
2. Start frontend: `npm run dev`
126+
3. Connect MetaMask wallet
127+
4. Create profile → nonce `1`
128+
5. Update profile → nonce `2`
129+
6. Delete profile → nonce `3`
130+
131+
#### Automated Testing
132+
```bash
133+
# Backend tests
134+
cargo test
135+
136+
# Frontend tests
137+
npm test
138+
```
139+
140+
### Deployment Checklist
141+
142+
- [ ] Database migration applied
143+
- [ ] SQLX cache updated (`cargo sqlx prepare`)
144+
- [ ] Environment variables configured
145+
- [ ] CORS settings updated for frontend domain
146+
- [ ] Rate limiting configured (recommended)
147+
148+
### Security Considerations
149+
150+
- **Rate Limiting**: Implement rate limiting on nonce/auth endpoints
151+
- **Monitoring**: Log authentication failures and nonce patterns
152+
- **Database Constraints**: Consider adding nonce validation constraints
153+
- **Audit**: Regular security audits of authentication flow
154+
155+
### Future Enhancements
156+
157+
- **Nonce Expiration**: Add time-based nonce expiration
158+
- **Concurrent Request Handling**: Database-level atomic nonce operations
159+
- **Advanced Monitoring**: Authentication metrics and alerts
160+
- **Multi-device Support**: Handle multiple simultaneous sessions
161+
162+
## Conclusion
163+
164+
This implementation provides robust protection against replay attacks while maintaining a smooth user experience. The dynamic nonce system ensures that each authentication request is unique and cannot be reused, significantly improving the security of the SIWE authentication flow.
165+
166+
For questions or contributions, please refer to the implementation code or create an issue in the repository.

0 commit comments

Comments
 (0)