Skip to main content

Overview

The GenLayer Points API uses Sign-In With Ethereum (SIWE) for authentication. This allows users to authenticate using their Ethereum wallet (MetaMask, WalletConnect, etc.) without passwords.
Authentication endpoints use /api/auth/ prefix (not /api/v1/).

Authentication Flow

Step 1: Get Nonce

Request a nonce to include in the SIWE message.
curl -X GET https://tally.genlayer.com/api/auth/nonce/

Response

nonce
string
required
Random 32-character string valid for 5 minutes
{
  "nonce": "aB3dEf9hIjKlMnOpQrStUvWxYz012345"
}

Step 2: Create SIWE Message

Construct a SIWE message following the EIP-4361 standard:
tally.genlayer.com wants you to sign in with your Ethereum account:
0x1234567890abcdef1234567890abcdef12345678

Sign in with Ethereum to Tally

URI: https://tally.genlayer.com
Version: 1
Chain ID: 1
Nonce: aB3dEf9hIjKlMnOpQrStUvWxYz012345
Issued At: 2024-03-03T12:00:00Z
The address on line 2 must be in lowercase.

Step 3: Sign Message

Use the user’s wallet to sign the message:
const accounts = await window.ethereum.request({ 
  method: 'eth_requestAccounts' 
});
const address = accounts[0];

const message = `tally.genlayer.com wants you to sign in with your Ethereum account:\n${address.toLowerCase()}\n\nSign in with Ethereum to Tally\n\nURI: https://tally.genlayer.com\nVersion: 1\nChain ID: 1\nNonce: ${nonce}\nIssued At: ${new Date().toISOString()}`;

const signature = await window.ethereum.request({
  method: 'personal_sign',
  params: [message, address]
});

Step 4: Login with Signature

Send the signed message to the login endpoint.
curl -X POST https://tally.genlayer.com/api/auth/login/ \
  -H "Content-Type: application/json" \
  -d '{
    "message": "tally.genlayer.com wants you to...",
    "signature": "0xabcdef...",
    "referral_code": "ABC12345"
  }'

Request Body

message
string
required
The SIWE message that was signed
signature
string
required
The signature from the wallet (0x-prefixed hex string)
referral_code
string
Optional 8-character referral code for new users

Response

authenticated
boolean
Whether authentication was successful
address
string
The Ethereum address that was authenticated
user_id
integer
The user’s ID in the system
created
boolean
Whether this is a newly created user
session_key
string
Session identifier (for debugging)
referral_code
string
User’s unique referral code
referred_by
object
Information about who referred this user (if any)
{
  "authenticated": true,
  "address": "0x1234567890abcdef1234567890abcdef12345678",
  "user_id": 42,
  "created": true,
  "session_key": "abc123sessionkey",
  "referral_code": "XYZ78901",
  "referred_by": {
    "id": 10,
    "name": "Alice",
    "address": "0xabcdef...",
    "referral_code": "ABC12345"
  }
}

Verify Authentication Status

Check if the current session is authenticated.
cURL
curl -X GET https://tally.genlayer.com/api/auth/verify/ \
  --cookie "sessionid=your_session_cookie"

Response

{
  "authenticated": true,
  "address": "0x1234567890abcdef1234567890abcdef12345678",
  "user_id": 42,
  "session_key": "abc123sessionkey"
}
If not authenticated:
{
  "authenticated": false,
  "address": null,
  "user_id": null
}

Logout

Clear the authentication session.
cURL
curl -X POST https://tally.genlayer.com/api/auth/logout/ \
  --cookie "sessionid=your_session_cookie"

Response

{
  "message": "Logged out successfully."
}

Refresh Session

Extend the session lifetime to prevent expiration.
cURL
curl -X POST https://tally.genlayer.com/api/auth/refresh-session/ \
  --cookie "sessionid=your_session_cookie"

Response

{
  "message": "Session refreshed successfully."
}

Session Management

Session Cookies

Authentication uses HTTP-only session cookies:
  • Cookie name: sessionid
  • Secure flag: true (HTTPS only in production)
  • SameSite: Lax
  • Lifetime: Configurable (default 2 weeks)

Making Authenticated Requests

fetch('https://tally.genlayer.com/api/v1/users/me/', {
  credentials: 'include' // Important!
})
Always include credentials (cookies) in your requests. Without credentials: 'include', authenticated endpoints will return 401 Unauthorized.

Error Responses

Invalid Signature

{
  "error": "Invalid signature: address mismatch"
}

Expired Nonce

{
  "error": "Invalid or expired nonce."
}

Missing Required Fields

{
  "error": "Message and signature are required."
}

Invalid Message Format

{
  "error": "Invalid message format: No nonce found."
}

Security Considerations

  • Nonces are valid for 5 minutes
  • Each nonce can only be used once
  • Nonces are automatically cleaned up after use
  • Signatures are verified using eth_account library
  • Address in message must match recovered address from signature
  • Addresses are stored in lowercase for consistency
  • Sessions use HTTP-only cookies (not accessible to JavaScript)
  • Secure flag enabled in production (HTTPS only)
  • Session expiration is enforced
  • Referral codes are validated during signup
  • Self-referral is prevented
  • Invalid codes don’t cause signup to fail

Best Practices

  1. Always check authentication status before making requests
  2. Handle wallet connection errors gracefully
  3. Store session cookies securely (HTTP-only)
  4. Implement session refresh for long-lived applications
  5. Clear sessions on logout to prevent unauthorized access

Next Steps

User Endpoints

Access user profile and data

Contributions

Submit and manage contributions

Build docs developers (and LLMs) love