GameFi
  • General Intro
  • 📃R & D
  • 💻Workshop
    • 🏎️NFT Web App Integration
      • 📄Prerequirements
      • Decentralized Storage
      • Smart Contract NFTs
      • Creating the React Dapp
      • Updating Startup File, Wallet Connect & Main Menu
      • Fetching NFTs, Stacks and Hiro API
      • Rendering NFTs owned
      • Selecting an NFT
      • Mapping Scenes
      • Creating the playable game
  • 🪙Trustless Rewards - M1
    • General idea
    • Flow Lobbies
    • Smart Contract
  • 🎨Customizable NFTs - M2
    • General Idea
    • Flow Customizable NFTs
    • Smart Contracts
      • Component
      • Customizable Wrapper
  • 🎁Lootbox on Chain - M3
    • General Idea
    • Tech Explained
    • Smart Contracts
      • Item
      • Lootbox
      • Lootbox Manager
  • 📝Message Signing
    • General Idea
    • GameFi Use Cases
    • App Explained
  • 🪵SFTs
    • General Idea & Base SFTs Static Deployments
    • Metadata Structure
    • Static Flow and Smart Contracts
    • Advanced SFTs Dynamic Deployments
    • Dynamic Flow and Smart Contracts
    • Dapp Integrating SFTs
      • Front End
      • Back End
    • Resources
  • ⚡Subnets
    • Overall for subnets
  • Roadmap
  • 💾Decentralized Storage
    • Gaia
    • Pinata
    • Host SFTs and NFTs into Pinata
    • Gaia integration to host game resources
  • 🔗External Knowledge
    • Getting Started
    • Hiro API
    • Stacks Docs
    • Clarity Book
    • Hiro Tutorials
Powered by GitBook
On this page
  • Repository Open Source
  • Sign In Front End
  • Sign In Handler Back End
  • Welcome and Refresh Handlers

Was this helpful?

  1. Message Signing

App Explained

PreviousGameFi Use CasesNextGeneral Idea & Base SFTs Static Deployments

Last updated 2 years ago

Was this helpful?

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.

📝
GitHub - BowTiedDeployer/message-signing-authenticationGitHub
Logo