The auth primitive Zcash didn't have. Non-custodial, drop-in, and built on what wallets already do.
The memo-challenge column is the floor. It lights up everywhere ZIP 321 does, which is every modern Zcash wallet. The signed-message column is what your favourite wallet implements today.
| Wallet | Memo challenge | Signed message | MetaMask Snap |
|---|---|---|---|
| Zodl | Yes | No | No |
| YWallet | Yes | Transparent only | No |
| Zingo | Yes | Transparent only | No |
| zcash-cli | Yes | Yes | No |
| Cake, Zenith, eZcash | Yes | No | No |
| MetaMask + ChainSafe Snap | No | No | Yes |
Wallet support data based on the full matrix in docs/wallets.md. Memo-challenge coverage is universal; the long tail of shielded wallets is rolled up into one row.
Every flow ends in a single session. The user picks whichever their wallet supports. The server does not care which.
<MemoSignIn /> on the client, issueMemoHandler + pollMemoHandler on the server, SiwzMemoProvider for NextAuth. No signmessage feature needed in the wallet; works with every ZIP 321 wallet.verifyTransparentSignature handles t-addrs via secp256k1 recovery; verifySaplingSignature is a plug-point for a future ZIP 304 verifier.Two route handlers, one NextAuth provider, one sign-in component, one sign-out component. That is the whole integration.
// app/api/auth/memo/issue/route.ts import { issueMemoHandler } from "@siwz/next-auth/memo"; export const POST = issueMemoHandler({ secret: process.env.NEXTAUTH_SECRET!, serviceAddress: process.env.SIWZ_SERVICE_ADDRESS!, network: "mainnet", }); // app/api/auth/memo/poll/route.ts import { pollMemoHandler } from "@siwz/next-auth/memo"; export const POST = pollMemoHandler({ secret: process.env.NEXTAUTH_SECRET! }); // app/api/auth/[...nextauth]/route.ts import NextAuth from "next-auth"; import { SiwzMemoProvider } from "@siwz/next-auth"; const handler = NextAuth({ providers: [ SiwzMemoProvider({ secret: process.env.NEXTAUTH_SECRET! }) ], }); export { handler as GET, handler as POST }; // app/SignIn.tsx (client) import { MemoSignIn, SignOut } from "@siwz/react"; import { signIn, signOut } from "next-auth/react"; <MemoSignIn onSuccess={({ identity, envelope }) => signIn("memo", { identity, envelope, redirect: false })} />; <SignOut onSignOut={() => signOut({ callbackUrl: "/" })} />;
Both consume the same @siwz/* packages. The point: SIWZ is a primitive, not a framework.
Accounting and payroll for shielded ZEC teams. Viewing-key books, batch payouts, P&L and CSV exports. Real SIWZ in real product code.
A Zcash-gated comments wall. The minimal integration: if you can build this on a Saturday, SIWZ is real infrastructure.
Independently usable. Pure TypeScript core, no Node-only deps, 59 tests.