# Sui Zklogin

> 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".

- Skill: `tomevault-io/sui-zklogin` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/sui-zklogin`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/sui-zklogin/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/sui-zklogin

---


# 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

```typescript
import { ZkLoginProvider } from '@mysten/zklogin';

const zkLogin = new ZkLoginProvider({
  network: 'testnet',
  provider: 'google' // or 'facebook', 'twitch'
});

// 1. Initiate login
async function login() {
  const { url, nonce } = await zkLogin.getLoginUrl();

  // Store nonce for later
  sessionStorage.setItem('zklogin_nonce', nonce);

  // Redirect to OAuth provider
  window.location.href = url;
}

// 2. Handle callback
async function handleCallback() {
  const params = new URLSearchParams(window.location.search);
  const jwt = params.get('id_token');
  const nonce = sessionStorage.getItem('zklogin_nonce');

  // Generate ZK proof
  const proof = await zkLogin.getProof(jwt, nonce);

  // Get SUI address
  const address = await zkLogin.getAddress(proof);

  return { proof, address };
}

// 3. Sign transactions
async function signTransaction(tx: Transaction) {
  const signedTx = await zkLogin.signTransaction(tx);
  return signedTx;
}
```

### Move Contract Support

```move
// 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

```typescript
// Complete zkLogin implementation

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() {
    // Generate nonce
    const nonce = generateNonce();
    localStorage.setItem('zklogin_nonce', nonce);

    // Get OAuth URL
    const authUrl = this.provider.getAuthUrl({
      nonce,
      redirectUrl: 'http://localhost:3000/callback'
    });

    // Redirect
    window.location.href = authUrl;
  }

  async handleCallback() {
    const params = new URLSearchParams(window.location.search);
    const jwt = params.get('id_token');
    const nonce = localStorage.getItem('zklogin_nonce');

    if (!jwt || !nonce) {
      throw new Error('Missing JWT or nonce');
    }

    // Generate ZK proof
    const proof = await this.provider.getProof(jwt, nonce);

    // Derive address
    const address = this.provider.getAddress(proof);

    // Store session
    localStorage.setItem('zklogin_proof', JSON.stringify(proof));
    localStorage.setItem('zklogin_address', address);

    return { address, proof };
  }

  async signAndExecuteTransaction(tx: Transaction) {
    const proof = JSON.parse(localStorage.getItem('zklogin_proof')!);

    const signed = await this.provider.signTransaction(tx, proof);

    const result = await this.client.core.executeTransaction({
      transaction: signed,
      signature: proof.signature
    });

    return result;
  }
}
```

## React Hook

```typescript
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:
```typescript
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](https://tomevault.io/claim/first-mover-tw) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-13 -->

