December 29, 2021

How to Build a One-Click Sign in Using MetaMask with PHP's Laravel


Social logins: we have all seen them, we have all used them. "Login with Facebook". "Login with Github".

If you have been around the Web3 community you may have come across a more recent player in the game: "Login with MetaMask". For instance, this is how you may sign up for OpenSea the biggest NFT marketplace for Ethereum and Polygon.

MetaMask is a crypto wallet for the Ethereum blockchain that also allows you to interact with dApps (decentralized apps). Specifically it allows dApps to verify that you are the owner of a certain Ethereum address which in turn will serve as your online identity.

This tutorial will show you how to implement a one-click MetaMask login using web3.js and a PHP backend. While we will be using Laravel and Vue in this tutorial, the principles of:

  • Signing a message in Javascript using web3.js, and
  • Verifying the signature in a PHP backend

…is absolutely transferable to any JS and PHP framework of your choice.

In order to follow along the steps in this tutorial you will need:

  • MetaMask installed as a browser extension with at least 1 account (no ETH needed!). If you do not already have MetaMask installed you may take a look at their website. — If you want to configure your QuickNode RPC to MetaMask, we have you covered there too.
  • A local development environment that allows you to run a fresh Laravel installation. Take a look at the excellent Laravel documentation to get started. In this tutorial I will be using the Installation Via Composer installation method, but feel free to use Laravel Sail (Docker) should you prefer. When using Laravel Sail you will need prefix all commands with ./vendor/bin/sail (ie ./vendor/bin/sail composer install instead of composer install); please refer to the official Laravel Sail documentation for more information on how to execute commands.
  • General knowledge and familiarity of running terminal commands (NPM/Composer installs)

We have the source code here as well for you to look at.

Setting Up the Project

Alright, let us get going!

First off, we will create a new Laravel project. As previously mentioned I will be using the composer create-project method. This works great if you already have PHP and Composer installed on your local machine. Checkout the official Laravel documentation for more available installation options.

Run the following command in your terminal to generate the project:

composer create-project laravel/laravel metamask-demo-app

Install Jetstream

To get a head start on the frontend, we will pull in the official Laravel package "Jetstream" which gives us a nice pre-baked dashboard that includes a login form!

Inside your newly created folder metamask-demo-app you may run:

composer require laravel/jetstream

Once installed, we will tell Jetstream to scaffold our application with the Inertia (Vue3) preset. This will include a stack of Vue 3 and Tailwind CSS.

php artisan jetstream:install inertia

Finally, let us install the newly added NPM dependencies and compile the assets:

npm install && npm run dev

Up and running

In order to get the new Laravel app up and running, we will need to add a database connection. Normally this would be a MySQL or PostgreSQL database, but for our demo purpose we can use a SQLite database by creating an empty file called database.sqlite in our database directory.

To do so, run the following command from the root of your project:

touch database/database.sqlite

We will also need to update our .env file to use the sqlite connection and comment out or remove the unused variables (important):


Finally, we can migrate our database migrations and serve our Laravel application to the browser!

php artisan migrate
php artisan serve

The last command should output something like:

Starting Laravel development server:

Opening that URL in your browser, you should be met with a default Laravel welcome screen.

Navigate to and you should see a Jetstream login form.

Congratulations 🎉 — we are now ready to start coding!

Preparing the Frontend

First things first — let us tweak the frontend a bit by adding our "Login with MetaMask button".

Open the file resources/js/Pages/Auth/Login.vue and add the following HTML after the logo template part (around line 5).

 between the root <template> tags, after the <template #logo>...</template> part

// resources/js/Pages/Auth/Login.vue

<div class="text-center pt-4 pb-8 border-b border-gray-200">
    <jet-button @click="loginWeb3">
        Login with MetaMask
<div class="py-6 text-sm text-gray-500 text-center">
    or login with your credentials…

As you may have noticed the button already has a click handler specified, for now add a new empty method called loginWeb3 after the existing submit method:

at the bottom between the <script> tags, add async loginWeb3 method

// resources/js/Pages/Auth/Login.vue
methods: {
    submit() {
        // ...
    async loginWeb3() {
        // Our Meta Mask integration goes here

If you compile it by running npm run dev in your terminal the result should look something like this:

Creating a Signature Request

Right now the button does not do anything. Let us fix that!

We will start by installing the NPM package web3 which we will need:

npm install web3

Now we are ready to fill in a bit of logic.

First, add these imports at the top of the <script> section:

At the top of the <script> section

// resources/js/Pages/Auth/Login.vue
import Web3 from 'web3/dist/web3.min.js'
import { useForm } from '@inertiajs/inertia-vue3'

Next update the empty loginWeb3 function so it looks like the following:

Replace the previously added async loginWeb3 method

// resources/js/Pages/Auth/Login.vue
async loginWeb3() {
    if (! window.ethereum) {
        alert('MetaMask not detected. Please try again from a MetaMask enabled browser.')

    const web3 = new Web3(window.ethereum);

    const message = [
        "I have read and accept the terms and conditions ( of this app.",
        "Please sign me in!"

    const address = (await web3.eth.requestAccounts())[0]
    const signature = await web3.eth.personal.sign(message, address)

    return useForm({ message, address, signature }).post('/login-web3')

Here is what we're doing in the above code:

  1. Ensure MetaMask is present in the current browser by checking the window.ethereum property is present. Otherwise alert the user. (lines 3-5)
  2. Prepare the message we want the user to sign. We might as well make this a bit useful, such as have the user accepting the Terms & Conditions for using the app. However it is absolutely up to you what you'd like to have the user sign. (lines 9-12)
  3. Request the user's accounts. This is the first popup our users will see, and they have to select which address to sign in with. (line 14)
  4. Make the user sign our message - in this case accept our T&C. (line 15)
  5. Finally, send the message, address & signature to the backend. (line 17)

With a little bit of luck, after compilation you should be able to see the following flow in you browser:

Quick aside:

When it comes to the signature message, we have found that there is a little quirk to beware of. At the time of writing, if you enter any message of exactly 32 characters, the message will be presented in HEX in MetaMask. As such the message "Hello world but a lil bit longer" becomes:

In reality it is not a huge problem, but in my case it ended up costing me a bit of extra hours and hair-pulling figuring why my message was not showing in plain text. Now you know!

Verifying the Signature

We have our signature ready, and we are sending it to the backend. Now we need to:

  • Verify the signature is authentic
  • Check if the address matches an existing user in our database or otherwise create a new user
  • Log the user in and redirect to the app dashboard

Let us get started.

Install dependencies

Before we get to the actual coding part, we will need to install a few dependencies.

composer require kornrunner/keccak --ignore-platform-reqs
composer require simplito/elliptic-php --ignore-platform-reqs

We are adding the --ignore-platform-reqs flag as composer would otherwise throw an error stating that the required ext-gmp extension is missing.

For this demo to work, the GMP extension is not required, and we can safely ignore it.

However, should you for any reason wish to install GMP anyway, you may find this gist helpful.

Prepare the users table

Open the database/migrations/2014_10_12_000000_create_users_table.php file and replace the up method with the following code:

# database/migrations/2014_10_12_000000_create_users_table.php
public function up()
    Schema::create('users', function (Blueprint $table) {
        $table->string('profile_photo_path', 2048)->nullable();

The changes we have made here are:

  • Added a eth_address field which will hold the user's ethereum address
  • Made name , email , email_verified_at and password nullable

Remember to refresh the database afterwards using:

php artisan migrate:fresh

The login logic

Open the routes/web.php file and add the following line:

Add in the bottom of the file - after the Route::middleware(['auth:sanctum', 'verified'])->get(...) part

# routes/web.php
Route::post('login-web3', \App\Actions\LoginUsingWeb3::class);

Note: We are using the routes/web.php file and not api.php because we will need access to the sesssion / cookie state in order to log in the user once authenticated.

Next let us go on and create the app/Actions/LoginUsingWeb3.php file which will hold the actual login logic. Copy / paste the following code into it: 

# app/Actions/LoginUsingWeb3.php

namespace App\Actions;

use App\Models\User;
use Illuminate\Http\Request;
use Elliptic\EC;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use kornrunner\Keccak;

class LoginUsingWeb3
    public function __invoke(Request $request)
        if (! $this->authenticate($request)) {
            throw ValidationException::withMessages([
                'signature' => 'Invalid signature.'

            'eth_address' => $request->address

        return Redirect::route('dashboard');

    protected function authenticate(Request $request): bool
        return $this->verifySignature(

    protected function verifySignature($message, $signature, $address): bool
        $messageLength = strlen($message);
        $hash = Keccak::hash("\x19Ethereum Signed Message:\n{$messageLength}{$message}", 256);
        $sign = [
            "r" => substr($signature, 2, 64),
            "s" => substr($signature, 66, 64)

        $recId  = ord(hex2bin(substr($signature, 130, 2))) - 27;

        if ($recId != ($recId & 1)) {
            return false;

        $publicKey = (new EC('secp256k1'))->recoverPubKey($hash, $sign, $recId);

        return $this->pubKeyToAddress($publicKey) === Str::lower($address);

    protected function pubKeyToAddress($publicKey): string
        return "0x" . substr(Keccak::hash(substr(hex2bin($publicKey->encode("hex")), 1), 256), 24);

There is a few things going on here, so let us break it down step-by-step.

The _invoke method

This is the entry-point for the route that we registered, and will receive the POST request sent from our frontend.

The actual logic is quite straight forward as we:

  • Validate the signature sent from the frontend
  • Find or create new user based on the user's address. When creating a new user, we will make sure to store the address in our dedicatedeth_address field.
  • Log the user in, and redirect to the Jetstream dashboard

The verifySignature method

This is a standardized way of cryptographically validating that an Ethereum signature matches the corresponding message and address that signed it.

It is functionally equivalent to web3.eth.personal.ecRecover which returns the signing address of a message + signature.

We will not fully go into the nitty gritty details of this code, (I am not a mathematician, and you do not need to be one either) but the high level explanation is that we are:

  • Reconstructing a hash of the message
  • Extracting the public key from the signature and hashed message
  • Extracting the address from the public key
  • Checking that the address sent from the frontend actually matches the address that signed the message

And voilá! We now have a functioning login!

If you go back to your browser and go through the login flow, you should now be redirected to the dashboard.

Bonus tip: disable Jetstream registration

If you actually intend to use Jetstream for your app and want to make sure your users always register with MetaMask the first time they login, you may wish to disable the default /register route that Jetstream ships with.

You can open config/fortify.php and comment out the "registration feature" line:

# config/fortify.php
'features' => [
    // Features::registration(),

Your users will now only be able to register using the MetaMask login.


That is it folks!

In this tutorial we have built a simple login flow using Vue, Web3, MetaMask and Laravel.

I hope it has conveyed the basic workflow of how to integrate with a wallet, and how to use signatures to securely authenticate a user's identity server-side as well.

Given the decentralized nature of Web3, you will probably want to support more wallets that just MetaMask. For instance adding WalletConnect would allow using mobile-wallets to sign in by scanning a QR code.

For further exploration into supporting more wallets, you may wish check out these resources:

Subscribe to our newsletter for more articles and guides on Ethereum. If you have any feedback, feel free to reach out to us via Twitter. You can always chat with us on our Discord community server, featuring some of the coolest developers you will ever meet :)
Ready to try QuickNode? Start your 7-day free trial

Related articles 47

Dec 29, 2021 How to integrate IPFS with Ethereum

It can be costly to store massive files on a blockchain mainnet, and this is where decentralized file storing systems like IPFS can come in handy. Sometimes, NFTs use IPFS as well. In this guide, we’ll cover how we can integrate IPFS with...

Continue reading
Dec 29, 2021 How to generate a new Ethereum address in PHP

PHP is very popular in developing the backend of websites or web applications. PHP has a huge crowd of developers trusting it as their go-to language. In this guide, we will see how we can generate a new Ethereum address in...

Continue reading
Dec 29, 2021 Estimating gas price using pending transactions in Python

To send a transaction on the Ethereum network, you need to pay fees for including the transaction in a block as well as the computation necessary in the transaction; this fee is called gas. The transactions are accepted into the block based on the amount of gas they are...

Continue reading
Dec 29, 2021 How to connect to Ethereum network with ethers.js

When someone thinks of developing a dApp the first tool that comes to their mind is web3.js which is pretty common because of its popularity in the community and wide use cases, dApp development has been consistently growing and there are a lot of developers who want to...

Continue reading
Dec 29, 2021 How to connect to the Ethereum network using Ruby

Ruby has a huge fanbase. Ruby was developed by its creator with an intention to create a language people can have fun using. Ruby has been largely accepted by the developers all around the world since it’s launch, in fact, the biggest tech communities in many cities are...

Continue reading
Dec 29, 2021 How to generate a new Ethereum address in Ruby

With high usage in web applications and straightforward syntax, Ruby is used by a vast number of people. This guide will cover creating an Ethereum address in Ruby using ruby-eth...

Continue reading
Dec 29, 2021 How to connect to Ethereum network using Java / Web3j

We can say that Java is one of the most versatile languages out there, and it continues to be relevant in today's time. Java is so popular because of its massive user base and use cases. In this guide/tutorial, we'll learn how to connect to the Ethereum Blockchain network...

Continue reading
Dec 29, 2021 How to connect to Ethereum using .NET (Nethereum)

Dotnet or .NET is very popular for the development of desktop applications, most Windows desktop applications are built using .NET, and it also contributes largely to web application’s tech stack. In this guide, let’s see how we can connect to Ethereum using .NET and

Continue reading
Dec 29, 2021 How to Setup Local Development Environment for Solidity

The success story of blockchain started with Bitcoin and was given wings by Ethereum. Ethereum was the first blockchain to introduce programmable software to the immutable ledger; these programs that live on the blockchain are called smart contracts. Solidity is the...

Continue reading
Dec 29, 2021 How to deploy a smart contract with Brownie

Python is one of the most versatile programming languages; from researchers running their test models to developers using it in heavy production environments, it has use cases in every possible technical field. In today's guide, we will learn about Brownie, a Python-based...

Continue reading
Jan 27, 2022 How to Set Up a Near Project from Scratch

In this tutorial we will look at how we can setup a basic NEAR project from scratch, installing and configuring dependencies and customizing the project to work well with AssemblyScript.We will first start by initializing our project with a package.json file using...

Continue reading
Dec 29, 2021 Como crear y lanzar un ERC-721 (NFT)

Coleccionables digitales que son compatibles con ERC-721 se han vuelto muy populares desde el lanzamiento de Cryptokitties y han ganado adopción masiva en los últimos meses. Esta guía cubrirá la parte de creación y lanzamiento...

Continue reading
Dec 29, 2021 How to Build Your DApp Using The Modern Ethereum Tech Stack: Hardhat and EthersJs

When building a smart contract on the Ethereum blockchain, new developers tend to reach out to tools like truffle and web3.js in building their smart contracts. This tutorial will look at how to use Hardhat and Ether.js, which are now becoming the standard in building...

Continue reading
Dec 29, 2021 The Web3 Developer Stack

A developer stack is a bag of technologies a developer possesses. For example, MEAN (MongoDB, Express.js, AngularJS/Angular, and Node.js) and MERN (MongoDB, Express.js, React, and Node.js) are common web developer stacks. Similarly, today we will learn more about the web3...

Continue reading
Jan 10, 2022 How to Send a Transaction On Solana Using JavaScript

Hello reader! Today is an exhilarating day because we are going on an expedition to the Solana Blockchain. Solana is an up-and-coming blockchain seeking to improve upon the current ecosystem's solutions to the complex problem of providing a secure, scalable, decentralized...

Continue reading
Dec 29, 2021 How to do a non-custodial transaction with QuickNode

Private keys are one of the most sensitive pieces of data when it comes to cryptography and the blockchain. However, there has always been debate/confusion about choosing between custodial wallets (where the wallet provider has custody of the user’s private key) and...

Continue reading
Jan 10, 2022 How to Mint An NFT On Solana

Hello reader! Welcome to another Solana guide. Solana is an up-and-coming blockchain that seeks to solve the scalability issues that Ethereum has been handling. In this guide, you will walk through step-by-step how to create an NFT on Solana....

Continue reading
Dec 29, 2021 How to connect to the Ethereum network using Python using

You can build Ethereum applications in different programming languages. In this article, we will connect to the Ethereum network using Python.PrerequisiteEthereum Node (We will use QuickNode’s free...

Continue reading
Dec 29, 2021 How to Connect to Terra with JavaScript using Terra.js

Stablecoins have been bridging the gap between traditional currencies and blockchains. Stablecoins offer stable price tokens pegged by a reserve asset which is often a fiat current like USD, EUR, GBP. The Terra protocol provides a framework to work with stablecoins. This...

Continue reading
Dec 29, 2021 Introduction to Scaffold-ETH 🏗

Developing applications involves juggling several moving pieces like front-ends, back-ends, and databases. But developing a decentralized application on a blockchain adds a few more elements like smart contracts and nodes that allow you to connect to the...

Continue reading
Dec 29, 2021 How To Fork Ethereum Mainnet with Hardhat

Forking the chain at an older block of the blockchain is helpful if you want to simulate the blockchain’s state at that block; Hardhat has this functionality built in. In this guide, let’s go through the process of forking the Ethereum Mainnet at an older...

Continue reading
Dec 29, 2021 How to create and deploy a smart contract with Hardhat

Ethereum development environments like Truffle and Hardhat make it easier to work with smart contracts and Ethereum nodes. They provide a set of tools to seamlessly write, test, and deploy...

Continue reading
Dec 29, 2021 How to generate a new Bitcoin address in JavaScript

To do any type of transaction on the Bitcoin blockchain, you’ll need a public key or a Bitcoin address. In this guide, we’ll cover how to generate a new Bitcoin address in JavaScript using CyrptoCoinJS.

Continue reading
Dec 29, 2021 How to create your own DAO with Aragon

Blockchain provides us with the power of decentralization. Decentralization means the transfer of power to users/members rather than having a single centralized authority governing everything; it enables various use cases in finance, governance, voting, fundraising, etc....

Continue reading
Dec 29, 2021 How to Send an EIP-1559 Transaction

While Ethereum has been trying to scale, it has encountered some gas price issues. Many layer 2 solutions and sidechains sprang into existence to solve this problem, but Ethereum is the main chain, and at some point, it has to be improved. EIP-1559 was introduced to...

Continue reading
Dec 29, 2021 Como crear un NFT en SOLANA

¡Hola querido lector! Bienvenidos a una nueva guía de Solana.Solana es una blockchain que promete mucho a la hora de intentar resolver los problemas de escalabilidad que podemos apreciar en otras blockchains, como Ethereum por...

Continue reading
Jan 10, 2022 Como crear un Token BEP20

BEP20 es en Binance Smart Chain el equivalente al popular token ERC20 de la red de Ethereum. La diferencia es que el token BEP20 no corre en la red de Ethereum sino en la red de Binance Smart Chain. Más allá de esta diferencia, como BSC (Binance Smart Chain) implementa la...

Continue reading
Jan 10, 2022 How to Create an Address in Solana using JavaScript

Hello reader! Welcome to QuickNode's first Solana guide. Solana is an up-and-coming blockchain that seeks to solve the scalability issues that Ethereum has been handling. You will walk through step-by-step how to create a Solana address using the @solana/web3.js...

Continue reading
Jan 21, 2022 How to send a transaction on Terra using JavaScript and Terra.js

Terra has emerged as the choice of blockchain for developing a stablecoin based dApp. Terra provides a cutting-edge stablecoin framework for modern dApp development. In this guide, we will learn how to send a transaction on Terra using their javascript library...

Continue reading
Jan 21, 2022 How to create a token on Terra using Terra Station

Terra is the stablecoins framework with a pool of tokens to work with. Today in this guide, we will learn how to create our own token on the Terra blockchain network.PrerequisitesA Terra Bombay testnet...

Continue reading
Jan 26, 2022 How to Deploy an NFT on Solana Using Candy Machine V2

Hello readers, in this guide we are going to go into how to set up an NFT mint on Solana using Candy Machine v2. Previously we had a guide up on the V1, but it is now deprecated and is no longer in use for new mints.Candy Machine v2 has some...

Continue reading
Dec 27, 2021 How to Build a Wallet Generator for Solana in React

In this practical guide you will build a basic Wallet application with React and Web3 that will interact with Solana Network.This application will do the following operations:Connect to the...

Continue reading
Dec 29, 2021 How to Connect Your Dapp With MetaMask Using Ethers.js

In our dApp, we will have a simple react user interface that has a material button asking the user to connect to MetaMask. And if they do not have an account, they can create one or log in to their account. They will then view their wallet balance and address displayed on...

Continue reading
Dec 29, 2021 How to re-send a transaction with higher gas price using ethers.js

Sometimes, you submit a transaction on Ethereum without enough gas due to network congestion or too many pending transactions offering a higher gas price than you have offered on your transaction. If you have a high priority transaction but low gas, you could end up...

Continue reading
Dec 29, 2021 How to get the balance of an ERC-20 token

When a new token is made on the Ethereum network, it usually follows a specification. The most popular of which is the ERC20 specification. To meet this ERC20 standard, one's token must have a multitude of...

Continue reading
Dec 29, 2021 How to connect to Ethereum network with Web3.js

Libraries and frameworks make the development process a lot easier and faster. When it comes to Ethereum development, Web3.js is the go to library. That's because Web3.js is the official library, from the

Continue reading
Dec 29, 2021 How to Fork Ethereum Blockchain with Ganache.

Forking and running a local simulated Ethereum environment is essential if you want to work with DeFi or do Ethereum development in general. In this guide, we’ll cover how to fork Ethereum Blockchain with

Continue reading
Dec 29, 2021 How to fetch Ethereum event logs in Ruby

Ethereum log records are very useful to understand and keep track of smart contract events. In this guide, we are going to learn how to fetch ethereum event logs in Ruby using ethereum.rb ruby...

Continue reading
Dec 29, 2021 How to generate a new Ethereum address in Go

Golang is very popular among backend developers for building infrastructures and microservices. Go is a procedural programming language. Developed in 2007 by Robert Griesemer, Rob Pike, and Ken Thompson at Google, then launched in 2009 as...

Continue reading
Dec 29, 2021 How to generate a new Ethereum address in Python

Python is one of the most versatile programming languages out there with an abundance of use cases; We can build many applications with Python from client-side to back end. In this guide, we will cover creating an Ethereum address in Python using the

Continue reading
Dec 29, 2021 How to generate a new Ethereum address in JavaScript

When it comes to programming, there’s hardly anyone who has not used or heard about JavaScript. JavaScript was initially created for client-side scripting but has become a full-featured Object-Oriented...

Continue reading
Dec 29, 2021 How to connect to Ethereum network using Go

Go helps you make faster scalable backends and this guide will show you how to connect your backend to Ethereum (and make it even faster, more reliable, and globally accessible, all thanks to QuickNode’s global infrastructure). What is...

Continue reading
Dec 29, 2021 How to connect to Ethereum using PHP

PHP is a very popular choice among developers and has a vast community due to its long presence in web development. In this guide, we’ll cover how to connect to Ethereum with PHP using the web3.php...

Continue reading
Dec 29, 2021 How to use Subspace with QuickNode

In this guide, we'll understand a bit about reactive development and how to use Subspace with QuickNode.JavaScript is the programming language behind most of the internet apps and websites. JavaScript today has become one of the most used programming languages,...

Continue reading
Dec 29, 2021 Integrate Your Svelte App with a Smart Contract

Today we will be building a sample app in Svelte, and connecting it to a smart contract that we deploy on the Ropsten Network.Our frontend will be able to do the following:Allow the user to send a greeting message along with a wave to the...

Continue reading
Dec 29, 2021 Como crear un NFT en Solana usando Candy Machine

¡Hola querido lector! Hemos recibido un montón de pedidos por otra guía de NFT en Solana. En la guia anterior no llegamos hasta la parte mas jugosa, que es la parte donde enlazamos una...

Continue reading
Jan 17, 2022 How to Mint an NFT on Solana Using Candy Machine

NOTE: This guide is based off of the V1 of Candy Machine. V1 has been deprecated. You can catch an up-to-date guide on V2 here

Continue reading