Hey there, are you tired of dealing with clunky and outdated authentication methods for your web2 apps? Look no further than Solana! In this guide, we'll show you how to implement Solana's cutting-edge authentication features in your web2 app in a few simple steps.
First, let's set up the frontend. We'll be using Next.js and TypeScript for this example. Here's the code for creating a login transaction:
const createLoginTx = async (wallet: WalletContextState) => {
// A message that will be included in the login transaction
// You can change it to anything you like, in this case it's "YOUR_SIGN_MESSAGE"
const loginSignMessage = "YOUR_SIGN_MESSAGE";
// A unique code that will be included in the login transaction
// This code is generated by taking the current time in milliseconds, dividing it by 12e4 (1200,000)
// and taking the floor of the result
// This ensures that the code changes every 20 minutes
const code = Math.floor(Date.now() / 12e4);
// Encode the message and the code as a Uint8Array
const msg = new TextEncoder().encode(`${loginSignMessage} ${code}`);
// Get the public key from the wallet object
const pk = wallet.publicKey;
// Check if the wallet object has a public key and a signMessage method
if (!pk || !wallet.signMessage) {
throw new Error("Wallet does not support signMessage");
}
// Sign the message using the wallet's signMessage method
const signed = await wallet.signMessage(msg);
// Send a post request to the backend, including the public key and the encoded signature
await axios.post(`/web3/auth/v2/${pk.toBase58()}`, {
signature: encode(signed),
});
};
This line of code
const code = Math.floor(Date.now() / 12e4);
is responsible for generating a unique code every 20 minutes. It takes the current time in milliseconds using Date.now() and divides it by 12e4 (1200,000) to get the number of 20-minute intervals since January 1st, 1970. The Math.floor() function is then used to round down to the nearest whole number. This ensures that the code changes every 2 minutes, providing a time-stamped code to be included in the login transaction for authenticity and integrity checking.
On the backend, we'll use the following code to verify the signature:
const nacl = require('tweetnacl');
const bs58 = require('bs58');
const express = require('express');
const app = express();
app.post('/web3/auth/v2/:publicKey', (req, res) => {
const { publicKey } = req.params
const { signature } = req.body
// check if the request contains the publicKey and signature
if (!publicKey || !signature) throw new Error('Invalid request')
// message to be verified
const loginSignMessage = 'YOUR_SIGN_MESSAGE'
// code generated by the backend
const code = Math.floor(Date.now() / 12e4)
//encode the message and the code
const msg = new TextEncoder().encode(`${loginSignMessage} ${code}`)
//decode the publicKey and the signature
//verify the signature
const ok = sign.detached.verify(msg, decode(signature), decode(publicKey))
//if the signature is not verified throw an error
if (!ok)
throw new Error(
'Invalid signature, please try again or contact support if the problem persists.'
)
/* TO DO Your Session Codes */
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
The backend first checks if the request contains the publicKey and signature, if it doesn't it throws an error. Then it defines the message to be verified, constructed by "YOUR_SIGN_MESSAGE" and the code generated by the backend, encodes the message and the code, decodes the publicKey and the signature, verifies the signature, and if the signature is not verified, it throws an error. In this way, the backend can ensure that the message was signed by the correct person and that it hasn't been tampered with, providing a secure way for the user to authenticate in the Web2 app.
In summary, the backend code uses the publicKey and the signature sent by the client to verify the authenticity of the message and the integrity of the code, by comparing it with the one generated by the backend, providing a secure and reliable way for users to authenticate in the Web2 app using Solana.