A Web3 authentication system that avoids server-side storage of Ethereum addresses by using non-transferable Soulbound Tokens (SBTs) and hashed account identifiers.
Traditional Web3 authentication often requires storing wallet addresses in databases, creating privacy concerns and potential liability. This implementation explores an alternative approach using Soulbound Tokens to maintain persistent identity without address storage. This is a simple AI generated pseudocode example implementation, not representative of the Soulbound Finance implementation.
Instead of storing Ethereum addresses, the system:
- Validates ownership through ephemeral signatures
- Issues non-transferable SBTs as identity markers
- Generates hashed Account IDs that cannot be reversed to addresses
- Stores only these Account IDs in the database
The Account ID uses multi-layer hashing as a stub out and example of use for ZKP KYC, account IDs, and other data as may be needed:
function _generateAccountId(address owner, uint256 tokenId)
private pure returns (bytes32)
{
bytes32 layer1 = keccak256(abi.encodePacked(owner, tokenId));
bytes32 layer2 = keccak256(abi.encodePacked(layer1, "SBA_PRIVACY_SALT_V1"));
return keccak256(abi.encodePacked(
uint128(uint256(layer2)),
uint128(uint256(layer1)),
"SOULBOUND_AUTH"
));
}┌─────────────────────────────────────────────────────┐
│ Web3 Client │
│ - Wallet connection and signature generation │
│ - SBT contract interaction │
│ - JWT token management │
└──────────────────┬──────────────────────────────────┘
│
┌──────────────────▼──────────────────────────────────┐
│ Backend Server │
│ - Signature verification │
│ - JWT issuance and validation │
│ - Account ID database (no addresses) │
│ - Role-based access control │
└──────────────────┬──────────────────────────────────┘
│
┌──────────────────▼──────────────────────────────────┐
│ SBT Smart Contract │
│ - Non-transferable token minting │
│ - Account ID generation │
│ - EULA/Terms hash storage │
└──────────────────────────────────────────────────────┘
- User connects wallet and signs authentication message
- Server validates signature without storing address
- Server checks blockchain for existing SBT
- Returns JWT with
hasSBT: false
- User accepts EULA/Terms
- User mints SBT through smart contract
- Contract generates unique Account ID
- Server stores Account ID (not address) in database
- Returns JWT with
hasSBT: true, accountId: <hash>
- User signs new authentication message
- Server validates signature
- Server retrieves Account ID from blockchain
- Returns JWT with Account ID for session management
The Soulbound Token contract implements:
- Non-transferable ERC721-like tokens
- Deterministic Account ID generation
- One token per address restriction
- EULA acceptance tracking
Key functions:
mintSBT(bytes32 eulaHash, uint8 version) returns (uint256 tokenId, bytes32 accountId)
getAccountInfo(address owner) returns (bool hasToken, bytes32 accountId, uint256 tokenId)The Node.js server provides:
- Signature verification endpoint
- JWT token generation and refresh
- Account ID based session management
- RBAC implementation using Account IDs
Example endpoints:
POST /auth - Authenticate with signature
POST /confirm-mint - Confirm SBT minting
POST /refresh - Refresh JWT token
GET /account - Get account information
JavaScript client library handles:
- Wallet connection
- Signature generation
- SBT minting transactions
- JWT token management
Basic usage:
const sba = new SoulboundAuthClient({
contractAddress: '0x...',
serverUrl: 'https://api.example.com'
});
const auth = await sba.connect();
if (!auth.hasSBT) {
await sba.mintSBT(eulaHash, version);
}- Hashed Account IDs (32 bytes)
- EULA acceptance records
- Role assignments
- Application metadata
- Ethereum addresses
- Transaction histories
- Wallet balances
- Any reversible identifier
- Account IDs are deterministic but non-reversible
- No account recovery if wallet is lost
- One SBT per address by design
- Gas costs for initial SBT minting
- Signature Validation: All signatures must be verified server-side
- Replay Protection: Include timestamps in signed messages
- Rate Limiting: Implement on authentication endpoints
- JWT Security: Use strong secrets and appropriate expiration times
Roles are assigned to Account IDs rather than addresses:
const roles = {
admins: ['0xabc...'], // Account IDs
moderators: ['0x123...']
};
function requireRole(role) {
return (req, res, next) => {
const accountId = req.user.accountId;
if (roles[role].includes(accountId)) {
next();
} else {
res.status(403).json({ error: 'Insufficient permissions' });
}
};
}CREATE TABLE accounts (
account_id TEXT PRIMARY KEY,
created_at INTEGER NOT NULL,
eula_hash TEXT NOT NULL,
eula_version INTEGER NOT NULL,
metadata TEXT
);
CREATE TABLE sessions (
session_id TEXT PRIMARY KEY,
account_id TEXT,
expires_at INTEGER,
created_at INTEGER
);
CREATE TABLE access_control (
account_id TEXT PRIMARY KEY,
role TEXT DEFAULT 'user',
permissions TEXT
);- Deploy the SBT contract:
npx hardhat run scripts/deploy.js --network localhost- Configure environment variables:
SBT_CONTRACT_ADDRESS=0x...
RPC_URL=http://localhost:8545
JWT_SECRET=your-secret-key- Start the server:
node server/index.js- Test signature validation thoroughly
- Verify Account ID generation consistency
- Ensure SBTs are truly non-transferable
- Validate JWT expiration and refresh logic
- Test RBAC with various role configurations
Potential enhancements to explore:
- Zero-knowledge proof integration for additional privacy
- Cross-chain SBT verification
- Account recovery mechanisms using social recovery
- Batch signature verification for performance
- Decentralized session management
This is an AI Psudo-code generated experimental implementation, not representative of the Soulbound Finance implementation. Issues and pull requests are welcome for improving the approach.
MIT License - See LICENSE file for details.
This implementation builds upon concepts from:
- ERC-721 token standard
- Soulbound token proposals (EIP-5192)
- JWT authentication patterns
- Privacy-preserving authentication research
This is an experimental authentication system. This is an AI pseudocode generated experimental implementation, not representative of the Soulbound Finance implementation. It has not been audited and should be thoroughly reviewed before any use. The approach trades some convenience (no account recovery) for privacy benefits.