App Explained
Repository Open Source
Sign In Front End
function SignIn() {
const [userDetails, setUserDetails] = useContext(AppContext);
const [isUserWelcomed, setIsUserWelcomed] = useState(null);
const [wallet, setWallet] = useState(userDetails || null);
const authenticate = async () => {
const token = uuidv4();
openSignatureRequestPopup({
message: token,
network: new StacksTestnet(), // for mainnet, `new StacksMainnet()`
appDetails: {
name: "My Message Signing App",
icon: window.location.origin + "/my-app-logo.svg",
},
onFinish: async (data) => {
console.log("Signature of the message", data.signature);
console.log("Use public key:", data.publicKey);
console.log("To send", data);
// console.log("Addr", publicKeyToBtcAddress(data.publicKey), publicKeyToAddress(AddressVersion.TestnetMultiSig, data.publicKey));
console.log("Addr2", getAddressFromPublicKey(data.publicKey, TransactionVersion.Testnet))
try {
await axios.post('/signin', {token, publicKey: data.publicKey, signature: data.signature})
const updatedWallet = getAddressFromPublicKey(data.publicKey, TransactionVersion.Testnet);
setWallet(updatedWallet);
localStorage.setItem('userDetails', updatedWallet);
setUserDetails(updatedWallet);
setIsUserWelcomed(true);
} catch (e) {
console.error("Failed to login", e);
}
},
});
}
openSignatureRequestPopup
creates the necessary data after the pop-up is confirmed. The data contains the publicKey and signature, both for the previous token created.
Then it saves the Stacks address locally and sends to the backend the token, publicKey and signature to the route signin
.
Sign In Handler Back End
Gets the token, signature and publicKey from the client, then verifies the message signature using verifyMessageSignatureRsv
from the @stacks/encryption
library.
If it fails, sends a 401 error status back, else create the cookie session which will be available for 120 seconds.
const {verifyMessageSignatureRsv} = require("@stacks/encryption");
const signinHandler = (req, res) => {
const {token, signature, publicKey} = req.body
console.log(req.body);
if (!verifyMessageSignatureRsv({message: token, publicKey, signature})) {
// If the username isn't present, return an HTTP unauthorized code
res.status(401).end()
return
}
// set the expiry time as 120s after the current time
const now = new Date()
const expiresAt = new Date(+now + 120 * 1000)
const wallet = getAddressFromPublicKey(publicKey, TransactionVersion.Testnet);
// create a session containing information about the user and the expiry time
const session = new Session(wallet, expiresAt)
// add the session information to the sessions map
sessions[token] = session;
// In the response set a cookie on the client with the name "session_cookie"
// and the value as the UUID we generated. We also set the expiry time
res.cookie("session_token", token, {expires: expiresAt})
res.end()
}
Welcome and Refresh Handlers
After the user gets a cookie session attributed, if he reloads the page or comes back later to the page, the /welcome
request will be made. The server checks that there are cookies, the session_token
cookie exists, the userSession exists and it didn't expire and sends as confirmation, if all of them are alright, a message Welcome address
. If any of the conditions was not met, the server returns the 401 error status.
This can be placed on any action done on the client side. If the client app has an action to collect resources, it will send a message to the server checking if the session is valid and if it is, will collect the resources. If not, will ask the user to confirm his identity again.
Last updated
Was this helpful?