How to Build a zkLogin-Powered SUI Move dApp: A Complete Developer’s Guide

·

Building decentralized applications (dApps) on the SUI blockchain has become increasingly accessible, especially with innovations like zkLogin simplifying user onboarding. This guide walks you through creating a fully functional SUI Move dApp — a secure digital notebook — using React for the frontend and Move for the smart contract logic. You'll learn how to integrate zkLogin to enable users to authenticate with familiar Web2 identity providers such as Google, all while maintaining Web3 security standards.

Whether you're new to SUI development or expanding your Move language expertise, this hands-on tutorial delivers practical insights into full-stack dApp creation with privacy-preserving login mechanisms.

👉 Discover how to securely manage digital identities in your next dApp project


Core Keywords


Prerequisites and Setup

Before diving into coding, ensure your development environment is properly configured. This section outlines essential tools and initial setup steps.

Clone the Boilerplate Code

Start by cloning the provided boilerplate repository, which includes foundational code for integrating zkLogin with React:

git clone https://github.com/dacadeorg/zk-login-boilerplate

Navigate into the project directory and install dependencies using Yarn:

cd zk-login-boilerplate
yarn install

Project Structure Overview

The boilerplate follows a standard React structure:

Understanding this layout helps streamline development and debugging.


Configuring Google OAuth for zkLogin

zkLogin leverages OAuth providers like Google to authenticate users without exposing private keys. Here’s how to set it up.

Create a Google Cloud Project

  1. Go to Google Cloud Console.
  2. Create a new project.
  3. Navigate to APIs & Services > Credentials.
  4. Click Create Credentials > OAuth client ID.
  5. Choose Web application as the application type.
  6. Add http://localhost:8080 as an authorized redirect URI.

After creation, securely store the Client ID and Client Secret.

Set Environment Variables

Create a .env file in the root directory and add the following:

REACT_APP_CLIENT_ID=your_google_client_id.apps.googleusercontent.com
REACT_APP_PROVER_URL=https://prover-dev.mystenlabs.com/v1
REACT_APP_REDIRECT_URL=http://localhost:8080
REACT_APP_OPENID_PROVIDER_URL=https://accounts.google.com/.well-known/openid-configuration
REACT_APP_FULLNODE_URL=http://127.0.0.1:9000
REACT_APP_PACKAGE_ID=0x3d133870aa4959c2804430d8d582d907537b521cff595fce865734abf96da560

These values configure OAuth flow, node connection, and contract deployment settings.


Running a Local SUI Testnet

To test your dApp locally, run a SUI validator node.

Start the Validator

Ensure you have the SUI binaries installed, then launch the local testnet:

RUST_LOG="off,sui_node=info" ./target/release/sui-test-validator

This command starts a local network with RPC endpoint at http://127.0.0.1:9000.

Configure SUI Client

Add and switch to the local network:

sui client new-env --alias localnet --rpc http://127.0.0.1:9000
sui client switch --env localnet

Verify the active environment:

sui client envs

Fund Your Development Account

Use the faucet to request test tokens:

export JASON=0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a
curl --location --request POST 'http://127.0.0.1:9123/gas' \
--header 'Content-Type: application/json' \
--data-raw "{ \"FixedAmountRequest\": { \"recipient\": \"${JASON}\" } }"

Check your balance:

sui client gas

You now have test SUI tokens for deploying contracts.


Developing the Move Smart Contract

Your dApp will use a simple Move module to manage user notes.

Initialize the Move Package

sui move new notes

This creates a new Move project under sources/.

Write the Notes Contract

Replace the default module with the following code:

#[lint_allow(self_transfer)]
module bityoume::notes {
    use std::string::String;
    use sui::tx_context::TxContext;
    use sui::object::{Self, UID};
    use sui::transfer;

    public struct Notes has key {
        id: UID
    }

    public struct Note has key, store {
        id: UID,
        title: String,
        body: String
    }

    fun init(ctx: &mut TxContext) {
        let notes = Notes { id: object::new(ctx) };
        transfer::share_object(notes)
    }

    public fun create_note(title: String, body: String, ctx: &mut TxContext) {
        let note = Note {
            id: object::new(ctx),
            title,
            body
        };
        transfer::transfer(note, tx_context::sender(ctx))
    }

    public fun delete_note(note: Note, _ctx: &mut TxContext) {
        let Note { id, title: _, body: _ } = note;
        object::delete(id)
    }
}

This contract allows users to create and delete personal notes stored as SUI objects.

Deploy to Local Network

Deploy the package using your funded address:

sui client publish --gas-budget 100000000

Record the returned PACKAGE_ID and shared object ID for use in frontend integration.


Frontend Integration with React

Now connect the Move contract to a user-friendly interface.

Initialize SUI Client

Create src/utils/suiClient.ts:

import { SuiClient } from "@mysten/sui.js/client";

const FULLNODE_URL = process.env.REACT_APP_FULLNODE_URL;
export const PACKAGE_ID = process.env.REACT_APP_PACKAGE_ID;

export const SUI_CLIENT = new SuiClient({ url: FULLNODE_URL });

👉 Learn how leading platforms handle secure blockchain interactions

Implement zkLogin Authentication

Create src/utils/authService.ts to manage user login via Google OAuth.

Key methods include:

Authentication flow:

  1. User clicks “Login with Google.”
  2. Redirected to Google’s OAuth page.
  3. After approval, Google returns a signed JWT.
  4. The JWT is processed to derive a SUI address and generate ephemeral keys.
  5. Users can now sign transactions without managing seed phrases.

Build Notes Service

Create src/utils/notesService.ts to interact with the deployed contract:

Transactions are signed using zkLogin-generated credentials, ensuring secure access control.


UI Components and Routing

Structure your app with clean navigation and responsive design.

Set Up Routes

Modify src/index.js:

<Router>
  <Routes>
    <Route path="/notes" element={<App />} />
    <Route path="/" element={<Callback />} />
  </Routes>
</Router>

The / route handles OAuth callbacks; /notes shows the main interface after login.

Handle OAuth Callback

Create src/Callback.js:

useEffect(() => {
  const params = new URLSearchParams(window.location.hash.substr(1));
  const jwtToken = params.get("id_token");
  sessionStorage.setItem("sui_jwt_token", jwtToken);
  window.location.href = "/notes";
}, []);

This captures the ID token and redirects to the protected notes dashboard.

Display User Notes

The Notes component fetches and renders user data using Bootstrap grid layout. Users can:

All actions trigger authenticated transactions via zkLogin.


Testing the dApp

Launch the app:

yarn start

End-to-End Flow

  1. Open http://localhost:8080.
  2. Click Login with Google.
  3. Approve authentication.
  4. Get redirected to /notes.
  5. Request test tokens for your derived wallet address.
  6. Create and delete notes freely.

Each transaction uses zkLogin credentials — no manual wallet extension required.


Frequently Asked Questions (FAQ)

What is zkLogin and why use it?

zkLogin allows users to log in using OAuth providers (e.g., Google) while deriving cryptographic identities via zero-knowledge proofs. It bridges Web2 ease-of-use with Web3 security, reducing friction in dApp adoption.

How does zkLogin enhance security?

Instead of storing private keys, zkLogin generates temporary keypairs and proves identity via ZK proofs. This minimizes exposure to phishing and key leakage risks.

Can I use other OAuth providers?

Yes! While this guide uses Google, zkLogin supports any OpenID Connect-compliant provider, including Facebook, Apple, or custom identity servers.

Is the Move contract secure?

The example contract is minimal but follows best practices: uses safe object ownership patterns, avoids reentrancy (not applicable in Move), and leverages SUI’s built-in access controls through sender verification.

How are user funds protected?

User assets are linked only to their zkLogin-derived address. Transactions require both JWT validation and ZK proof generation, ensuring only authenticated users can act on-chain.

Can I deploy this on SUI mainnet?

Yes. To go live:

👉 Explore advanced identity solutions used by top-tier dApps


By combining SUI Move, zkLogin, and React, you’ve built a modern, secure, and user-friendly dApp that exemplifies the future of decentralized application design — where usability meets robustness. This foundation can be extended to support NFTs, DeFi features, or social graphs, opening doors to innovative Web3 experiences.