| name | sui-zklogin |
| description | Use when implementing zkLogin on SUI — OAuth login (Google, Facebook, Apple, Twitch) with zero-knowledge proofs for privacy-preserving authentication. Triggers on "zkLogin", "social login on SUI", "Google login", "OAuth", "ephemeral keypair", "JWT proof", or any authentication flow that derives a SUI address from an OAuth provider. Also use when the user mentions "login without wallet extension". |
| metadata | {"author":"first-mover-tw"} |
SUI zkLogin Integration
OAuth-based wallet authentication with zero-knowledge proofs.
Overview
zkLogin allows users to:
- Login with Google, Facebook, Twitch, etc.
- No seed phrases or private keys to manage
- Wallet address derived from OAuth sub (user ID)
- Zero-knowledge proofs for privacy
Use Cases
- User onboarding (no wallet required)
- Social login for dApps
- Gaming platforms
- Mobile apps
- Mainstream user applications
Quick Start
Frontend Setup
import { ZkLoginProvider } from '@mysten/zklogin';
const zkLogin = new ZkLoginProvider({
network: 'testnet',
provider: 'google'
});
async function login() {
const { url, nonce } = await zkLogin.getLoginUrl();
sessionStorage.setItem('zklogin_nonce', nonce);
window.location.href = url;
}
async function handleCallback() {
const params = new URLSearchParams(window.location.search);
const jwt = params.get('id_token');
const nonce = sessionStorage.getItem('zklogin_nonce');
const proof = await zkLogin.getProof(jwt, nonce);
const address = await zkLogin.getAddress(proof);
return { proof, address };
}
async function signTransaction(tx: Transaction) {
const signedTx = await zkLogin.signTransaction(tx);
return signedTx;
}
Move Contract Support
// No special Move code needed!
// zkLogin addresses are regular SUI addresses
// Use tx_context::sender(ctx) as normal
public fun create_profile(
name: String,
ctx: &mut TxContext
) {
let user = tx_context::sender(ctx); // Works with zkLogin!
// Create user profile
// ...
}
Full OAuth Flow
import { ZkLoginProvider, generateNonce } from '@mysten/zklogin';
import { SuiGrpcClient } from '@mysten/sui/grpc';
class ZkLoginAuth {
private provider: ZkLoginProvider;
private client: SuiGrpcClient;
constructor() {
this.provider = new ZkLoginProvider({
network: 'testnet',
provider: 'google'
});
this.client = new SuiGrpcClient({ network: 'testnet' });
}
async login() {
const nonce = generateNonce();
localStorage.setItem('zklogin_nonce', nonce);
const authUrl = this.provider.getAuthUrl({
nonce,
redirectUrl: 'http://localhost:3000/callback'
});
.. = authUrl;
}
() {
params = (..);
jwt = params.();
nonce = .();
(!jwt || !nonce) {
();
}
proof = ..(jwt, nonce);
address = ..(proof);
.(, .(proof));
.(, address);
{ address, proof };
}
() {
proof = .(.()!);
signed = ..(tx, proof);
result = ...({
: signed,
: proof.
});
result;
}
}
React Hook
function useZkLogin() {
const [address, setAddress] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const login = async (provider: 'google' | 'facebook') => {
setIsLoading(true);
const zkLogin = new ZkLoginProvider({ network: 'testnet', provider });
const { url, nonce } = await zkLogin.getLoginUrl();
sessionStorage.setItem('nonce', nonce);
window.location.href = url;
};
const handleCallback = async () => {
const auth = new ZkLoginAuth();
const { address } = await auth.handleCallback();
setAddress(address);
setIsLoading(false);
};
return { address, login, handleCallback, isLoading };
}
Security Considerations
- NEVER expose OAuth client secrets in frontend
- Always validate JWT signatures
- Use secure nonce generation
- Implement session timeout
- Store proofs securely (encrypted storage)
Best Practices
- Support multiple OAuth providers
- Fallback to traditional wallet connection
- Clear session on logout
- Handle token expiration
- Provide visual feedback during auth
Common Mistakes
❌ Exposing OAuth client secret in frontend
- Problem: Security breach, anyone can impersonate your app
- Fix: Keep client secret server-side, use PKCE flow for frontend
❌ Not validating JWT signature
- Problem: Forged tokens, authentication bypass
- Fix: Always verify JWT with provider's public key
❌ Reusing nonce across sessions
- Problem: Replay attacks possible
- Fix: Generate fresh nonce for each login attempt
❌ Storing ZK proof in localStorage unencrypted
- Problem: XSS attacks can steal proof, drain wallet
- Fix: Encrypt proof before storage or use sessionStorage
❌ No fallback when OAuth provider is down
- Problem: Users locked out of app
- Fix: Offer traditional wallet connection as fallback
❌ Not handling token expiration
- Problem: Silent failures, broken transactions
- Fix: Implement token refresh or prompt re-authentication
Query latest zkLogin updates:
const zkLoginInfo = await sui_docs_query({
type: "github",
target: "zklogin",
query: "OAuth integration examples and best practices"
});
Seamless user onboarding with familiar OAuth login!
Converted and distributed by TomeVault — claim your Tome and manage your conversions.