Message signing and user authentication with Nautilus wallet and sigma-rust#
Did you know that besides transactions you can sign any piece of data? Here is how you do it using Nautilus wallet
const message = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const signature = ergo.sign_data('<your_addr>', message);
Yeah… but why? you may ask. Well, because now you can post it to your NodeJS backend application and do this, using sigma-rust:
import * as ergoWasm from 'ergo-lib-wasm-nodejs'
const isValid = ergoWasm.verify_signature(addr, message, signature);
if (isValid) { // authenticated!!! }
This is called wallet authentication - the way to verify that the user/client is the owner of the address he is claiming to be.
In SigmaValley we allow NFT owners to edit their plot information and upload custom models. So if isValid === true and the backend knows that the request came from the wallet owner, I can now request all the tokens on that address and provide the client with access to protected functionality or data.
const balance = await request
.get(`https://api.ergoplatform.com/api/v1/addresses/${addr}/balance/confirmed`)
.then(res => res.body);
if (balance.tokens.find(token => token.tokenId === '<valid token>') {
// Allow user break SigmaValley
}
You can use the same method to allow your users to upload their NFT as a character in your game or build an NFT-based ticketing system, the uses are limitless.
Next steps/security tips#
- User expiration mechanism - The example above is very simplified, you can use it right away, but for more secure applications you may consider implementing some message expiration mechanism. Instead of signing a random message, you can include an expiration date to it and force users to sign a new message once in a while. You can also switch to a more popular JTW token authentication once the user is verified.
- Check the token balance on every request - it's not enough to check whether the user holds the NFT only once. The user can get access and sell his NFT to someone else. It's a good idea to move the balance check and the verification to authentication middleware to be executed on every request to your protected routes.
References: