Documentation Index
Fetch the complete documentation index at: https://docs.shieldhq.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Authentication
SHIELD uses Sign-In with Ethereum (SIWE) for authentication. No passwords required—just your wallet.
SIWE Flow
┌──────────┐ ┌──────────┐
│ Client │ │ Server │
└────┬─────┘ └────┬─────┘
│ │
│ 1. Request nonce │
│ ───────────────────────────────▶│
│ │
│ 2. Return nonce │
│ ◀──────────────────────────────│
│ │
│ 3. Sign SIWE message │
│ (with nonce) │
│ │
│ 4. Send signature │
│ ───────────────────────────────▶│
│ │
│ 5. Verify signature │
│ │
│ 6. Return JWT session │
│ ◀──────────────────────────────│
│ │
│ 7. Use JWT for API calls │
│ ───────────────────────────────▶│
Endpoints
1. Get Nonce
Returns a unique nonce for signing.
Response:
{
"nonce": "1234567890abcdef"
}
2. Verify Signature
POST /api/verify-siwe
Content-Type: application/json
Request Body:
{
"message": "shield.app wants you to sign in...",
"signature": "0x..."
}
The message follows the EIP-4361 SIWE standard.
Response:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"address": "0x...",
"expiresAt": "2025-02-23T10:00:00Z"
}
3. Authenticated Requests
Include the JWT in subsequent requests:
GET /api/user/links
Cookie: session=eyJhbGciOiJIUzI1NiIs...
Or via Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
shield.app wants you to sign in with your Ethereum account:
0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
Sign this message to authenticate with SHIELD.
URI: https://app.shieldhq.xyz
Version: 1
Chain ID: 84532
Nonce: 1234567890abcdef
Issued At: 2025-02-22T10:00:00Z
Client Implementation
Using wagmi + siwe
import { SiweMessage } from 'siwe';
import { signMessage } from 'wagmi/actions';
async function authenticate(address: string, chainId: number) {
// 1. Get nonce
const nonceRes = await fetch('/api/signIn');
const { nonce } = await nonceRes.json();
// 2. Create SIWE message
const message = new SiweMessage({
domain: window.location.host,
address,
statement: 'Sign this message to authenticate with SHIELD.',
uri: window.location.origin,
version: '1',
chainId,
nonce,
});
// 3. Sign message
const messageString = message.prepareMessage();
const signature = await signMessage({ message: messageString });
// 4. Verify
const verifyRes = await fetch('/api/verify-siwe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: messageString, signature }),
});
return await verifyRes.json();
}
Using ethers.js
import { SiweMessage } from 'siwe';
import { ethers } from 'ethers';
async function authenticate(signer: ethers.Signer) {
const address = await signer.getAddress();
const nonce = (await fetch('/api/signIn').then(r => r.json())).nonce;
const message = new SiweMessage({
domain: 'shield.app',
address,
statement: 'Sign this message to authenticate with SHIELD.',
uri: 'https://app.shieldhq.xyz',
version: '1',
chainId: 84532,
nonce,
});
const signature = await signer.signMessage(message.prepareMessage());
const response = await fetch('/api/verify-siwe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: message.prepareMessage(),
signature,
}),
});
return await response.json();
}
Session Details
| Property | Value |
|---|
| Duration | 1 hour |
| Storage | HTTP-only cookie |
| Renewal | Automatic on activity |
| Revocation | On logout or expiry |
Security Considerations
Nonce Requirements
- Must be used within 5 minutes
- Single-use only
- Cryptographically random (32 bytes)
Signature Verification
Server verifies:
- Signature is valid
- Address matches recovered signer
- Nonce was issued by server
- Domain matches expected
- Chain ID is supported
Replay Protection
- Nonces are single-use
- Timestamps prevent old signatures
- Sessions expire after 1 hour
Error Codes
| Code | Meaning |
|---|
INVALID_SIGNATURE | Signature doesn’t match address |
EXPIRED_NONCE | Nonce older than 5 minutes |
USED_NONCE | Nonce already consumed |
DOMAIN_MISMATCH | Message domain doesn’t match |
UNSUPPORTED_CHAIN | Chain ID not supported |
Testing
Test Authentication
# 1. Get nonce
curl https://app.shieldhq.xyz/api/signIn
# 2. Sign message (use your wallet)
# 3. Send to verify-siwe