> For the complete documentation index, see [llms.txt](https://docs.megaeth.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.megaeth.com/moss-docs/wallet/server-verify.md).

# Server Verify

Two core functions. SIWE message generation + signature verification for MOSS wallet auth flows.

**install**

```bash
npm install @megaeth-labs/wallet-server-verify
```

## How It Works

1. **Server** generates challenge via `getMessageToSign()`.
2. **Client** signs the exact message with `mega.signMessage()`.
3. **Server** verifies with `verifySignature()` using the same config.

{% hint style="warning" %}
Always verify server-side before issuing app sessions. Never trust client-only signature checks.
{% endhint %}

## Complete Express.js Example

**server/auth.ts**

```typescript
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

| Error               | Meaning                                                              | Typical action                                            |
| ------------------- | -------------------------------------------------------------------- | --------------------------------------------------------- |
| `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.

| Network | chainId |
| ------- | ------- |
| Mainnet | `4326`  |
| Testnet | `6343`  |

## Exports and Types

This package exports core methods, typed payloads, and error constants:

| Export                                                 | Purpose                                                                                          |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| `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**

```typescript
type MegaETHNetwork = 6343 | 4326;

interface MessageConfig {
  scheme: 'http' | 'https';
  domain: string;
  uri: string;
  chainId: MegaETHNetwork;
  statement: string;
}

interface MessageToSign {
  address: Hex;
  message: string;
  nonce: string;
  issuedAt: Date;
}

interface MessageToConfirm extends MessageToSign {
  signature: Hex;
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.megaeth.com/moss-docs/wallet/server-verify.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
