NanChat Developer Docs
Integrate NanChat into your web app with universal links. No server-side dependency on NanChat. Everything works through public Nano cryptography.
Contents
Send Request
Use a universal link to open NanChat with the recipient address and amount already filled in. The user only needs to confirm the transaction. This works on iOS and Android.
URL format
https://nanchat.com/?uri=<PREFIX>:<ADDRESS>?amount=<RAW_AMOUNT>
PREFIX: one ofnano,ban,usd(NanUSD), or any other supported network prefix. This tells NanChat which network to use for the transaction.ADDRESS: the recipient address for that network (e.g.nano_...,ban_...,usd_...).RAW_AMOUNT: the amount in the smallest unit (raw) for that network. Optional.
Example: send NanUSD
https://nanchat.com/?uri=usd:usd_3i5ychrw4ajk5tj5y9ocwr5t9j3tej7t1bwrkcm6p3p1wsu5ny5q371d3bxh?amount=1000
Send Nano
https://nanchat.com/?uri=nano:nano_1banexkcfuieufzxksfrxqf6xy8e57ry1zdtq9yn7jntzhpwu4pg4hajojmq?amount=1000000000000000000000000000
HTML button
<a href="https://nanchat.com/?uri=nano:nano_3xxx...xxx?amount=1000000000000000000000000000000" style="text-decoration: none;">
<button style="display: inline-flex; align-items: center; gap: 8px; background: #000000; color: #fff; border: none; padding: 10px 18px; border-radius: 6px; font-size: 15px; font-weight: 600; cursor: pointer;">
<img src="https://bucket.nanwallet.com/logo/nanchat-pay-icon-01.svg"
alt="" width="20" height="20">
Pay with NanChat
</button>
</a>
Preview:
Login with NanChat
“Login with NanChat” lets a user prove ownership of a Nano address by signing a server-generated nonce. The signature is verified on your backend with the user’s public key. No password, no third-party identity provider.
Flow
- Your server generates a random
nonceand stores it in the user’s pending session. - You render a Login with NanChat button pointing to a
nanauth://signuniversal link wrapped byhttps://nanchat.com/?uri=. - The user opens the link. NanChat prompts them to sign the message.
- On success, NanChat calls your
urlcallback with the signature, account, and message. - Your
/callbackendpoint verifies the signature with nanocurrency-web, checks that the message contains the expected nonce, and issues a session cookie.
1. Build the login link
const nonce = crypto.randomBytes(16).toString('hex'); // store on the server
const message = `Login to xxxxx.com nonce: ${nonce}`;
const callback = 'https://xxxxx.com/callback';
const nanauth = `nanauth://sign?message=${encodeURIComponent(message)}` +
`&url=${encodeURIComponent(callback)}`;
const loginUrl = `https://nanchat.com/?uri=${encodeURIComponent(nanauth)}`;
Render it as a button:
<a href="https://nanchat.com/?uri=nanauth%3A%2F%2Fsign%3Fmessage%3DLogin%2520to%2520xxxxx.com%2520nonce%253A%2520NONCE%26url%3Dhttps%253A%252F%252Fxxxxx.com%252Fcallback" style="text-decoration: none;">
<button style="display: inline-flex; align-items: center; gap: 8px; background: #000000; color: #fff; border: none; padding: 10px 18px; border-radius: 6px; font-size: 15px; font-weight: 600; cursor: pointer;">
<img src="https://nanchat.com/images/nanchat.svg"
alt="" width="20" height="20">
Login with NanChat
</button>
</a>
Preview:
2. Verify the callback on your server
NanChat POSTs the signature payload to your url as JSON, with
account, signature, and message. Derive the public key
from the account with tools.addressToPublicKey, then verify the signature with
tools.verify from
nanocurrency-web:
import { tools } from 'nanocurrency-web';
app.post('/callback', express.json(), (req, res) => {
const { account, signature, message } = req.body;
// 1. The message must contain the nonce we issued for this session.
const expectedNonce = req.session.pendingNonce;
if (!message || !message.includes(`nonce: ${expectedNonce}`)) {
return res.status(400).json({ error: 'Invalid or expired nonce' });
}
// 2. Derive the public key from the claimed account.
const publicKey = tools.addressToPublicKey(account);
// 3. Verify the signature. NanChat signs the message prefixed with
// "Signed Message: " (standard Nano signed-message format).
const valid = tools.verify(publicKey, signature, 'Signed Message: ' + message);
if (!valid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// 4. Consume the nonce and issue a session cookie.
req.session.pendingNonce = null;
req.session.user = { account };
res.json({ ok: true });
});
- Nonces must be single-use, random (≥ 128 bits), and short-lived (e.g. 5 minutes) and is used to prevent replay attacks.
- Make sure to verify the signature against
"Signed Message: " + message
Questions or feedback?
Reach out at [email protected] or via NanChat Team on NanChat.