Server Verify
Backend SIWE verification for MOSS wallet signatures.
Two core functions. SIWE message generation + signature verification for MOSS wallet auth flows.
install
npm install @megaeth-labs/wallet-server-verifyHow It Works
Server generates challenge via
getMessageToSign().Client signs the exact message with
mega.signMessage().Server verifies with
verifySignature()using the same config.
Always verify server-side before issuing app sessions. Never trust client-only signature checks.
Complete Express.js Example
server/auth.ts
import express from 'express';
import crypto from 'node:crypto';
import jwt from 'jsonwebtoken';
import {
getMessageToSign,
verifySignature,
Errors,
type MessageConfig,
type MessageToConfirm,
type MessageToSign,
} from '@megaeth-labs/wallet-server-verify';
const app = express();
app.use(express.json());
const config: MessageConfig = {
scheme: 'https',
domain: 'yourapp.com',
uri: 'https://yourapp.com',
chainId: 4326,
statement: 'Sign in to YourApp',
};
const challenges = new Map<string, MessageToSign>();
// POST /auth/challenge
app.post('/auth/challenge', (req, res) => {
const challenge = getMessageToSign(config, req.body.address);
const challengeId = crypto.randomUUID();
challenges.set(challengeId, challenge);
res.json({
challengeId,
...challenge,
});
});
// POST /auth/verify
app.post('/auth/verify', async (req, res) => {
const { challengeId, signature } = req.body;
const stored = challenges.get(challengeId);
if (!stored) {
return res.status(400).json({ error: 'UNKNOWN_OR_EXPIRED_CHALLENGE' });
}
const signedMessage: MessageToConfirm = {
...stored,
signature,
};
try {
await verifySignature(config, signedMessage);
challenges.delete(challengeId);
const token = jwt.sign(
{ address: stored.address },
process.env.JWT_SECRET as string,
{ expiresIn: '1h' },
);
res.json({ ok: true, token });
} catch (error) {
if (error instanceof Error) {
if (error.message === Errors.DIFFERENT_MESSAGE) {
return res.status(400).json({ error: Errors.DIFFERENT_MESSAGE });
}
if (error.message === Errors.INVALID_SIGNATURE) {
return res.status(401).json({ error: Errors.INVALID_SIGNATURE });
}
}
return res.status(500).json({ error: 'UNKNOWN_ERROR' });
}
});Error Handling
DIFFERENT_MESSAGE
Submitted message payload does not match what your server generated.
Reject request and ask client to fetch a fresh challenge.
INVALID_SIGNATURE
The signature does not match the message/address pair.
Reject auth attempt.
Chain IDs Reference
Use the same chain ID in MessageConfig that your app uses for the target environment.
Mainnet
4326
Testnet
6343
Exports and Types
This package exports core methods, typed payloads, and error constants:
getMessageToSign(config, address)
Create a SIWE message payload plus nonce/issuedAt.
verifySignature(config, messageToConfirm)
Validate message integrity and signature via relay-backed verification.
Errors
Error constants: DIFFERENT_MESSAGE, INVALID_SIGNATURE, ACCOUNT_NOT_FOUND, ACCESS_DENIED.
MessageConfig / MessageToSign / MessageToConfirm
Typed contracts for challenge and verification payloads.
types.ts
Last updated