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
- SUI Move
- zkLogin
- SUI blockchain
- dApp development
- React frontend
- Smart contract
- Web3 authentication
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-boilerplateNavigate into the project directory and install dependencies using Yarn:
cd zk-login-boilerplate
yarn installProject Structure Overview
The boilerplate follows a standard React structure:
public/: Containsindex.html, the entry point of the app.src/: Houses core application logic including components, utilities, and services.utils/: Will contain helper functions for interacting with the SUI blockchain and zkLogin..env: Environment variables will be stored here for secure configuration.
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
- Go to Google Cloud Console.
- Create a new project.
- Navigate to APIs & Services > Credentials.
- Click Create Credentials > OAuth client ID.
- Choose Web application as the application type.
- Add
http://localhost:8080as 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=0x3d133870aa4959c2804430d8d582d907537b521cff595fce865734abf96da560These 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-validatorThis 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 localnetVerify the active environment:
sui client envsFund 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 gasYou 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 notesThis 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 100000000Record 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:
login(): Redirects user to Google for authentication.getWalletAddress(): Derives SUI address from JWT token.generateZkLoginSignature(): Produces zero-knowledge proof signature for transaction signing.
Authentication flow:
- User clicks “Login with Google.”
- Redirected to Google’s OAuth page.
- After approval, Google returns a signed JWT.
- The JWT is processed to derive a SUI address and generate ephemeral keys.
- Users can now sign transactions without managing seed phrases.
Build Notes Service
Create src/utils/notesService.ts to interact with the deployed contract:
addNote(title, body): Callscreate_note.getNotes(): Queries allNoteobjects owned by user.deleteNote(id): Invokesdelete_note.
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:
- View existing notes in responsive cards.
- Add new notes via modal form.
- Delete notes with one click.
All actions trigger authenticated transactions via zkLogin.
Testing the dApp
Launch the app:
yarn startEnd-to-End Flow
- Open
http://localhost:8080. - Click Login with Google.
- Approve authentication.
- Get redirected to
/notes. - Request test tokens for your derived wallet address.
- 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:
- Replace
.envvariables with mainnet endpoints. - Use production OAuth credentials.
- Deploy contract via
sui client publishon mainnet. - Host frontend on static hosting (e.g., Vercel, GitHub Pages).
👉 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.