azkey-sdk
v0.2.0
Published
TypeScript SDK for Solana zkLogin proof generation and account management
Maintainers
Readme
azkey-sdk
TypeScript SDK for Solana zkLogin proof generation and account management.
Installation
npm install azkey-sdk
# or
pnpm add azkey-sdkQuick Start
import { AccountManager } from 'azkey-sdk';
// Initialize
const manager = new AccountManager({
googleClientId: 'your-client-id.apps.googleusercontent.com',
solanaRpcUrl: 'https://api.mainnet-beta.solana.com'
});
// Get Google OAuth URL
const authUrl = manager.getAuthUrl();
window.location.href = authUrl;
// Handle OAuth callback
const code = new URLSearchParams(window.location.search).get('code');
const authResult = await manager.exchangeCode(code);
// Create account
const account = await manager.createAccount(authResult);
console.log('Account created:', account.address);
console.log('Session owner:', account.sessionOwner);Features
✅ OAuth Integration - Seamless Google Sign-In
✅ Account Derivation - Deterministic account IDs from identity
✅ ZK Proof Generation - Private proof generation (client-side)
✅ Account Recovery - Recover accounts without seed phrases
✅ Session Management - Ephemeral key management
✅ TypeScript Support - Full type safety
✅ Framework Agnostic - Works with any JavaScript framework
How It Works
Step 1: Authentication
User authenticates with Google, receiving a JWT.
Step 2: Account ID Derivation
SDK derives a unique, permanent account_id from the JWT:
account_id = hash(jwt.sub, jwt.aud)jwt.sub= Google's unique user ID (private)jwt.aud= Your app's OAuth client ID- Deterministic: same user always gets same account ID
Step 3: Proof Generation
Noir circuit generates a zero-knowledge proof:
- ✓ JWT signature is valid
- ✓ Account ID matches hash
- ✓ Private inputs never revealed on-chain
Step 4: Account Creation
Solana program deployed with immutable account_id in account state.
Step 5: Session Management
Temporary session_owner key authorized to control account. Lost key? Use Google OAuth again to recover and set new owner.
API
AccountManager
Main entry point for account operations.
Constructor
new AccountManager(config: AccountConfig, provider?: string)Config:
{
googleClientId: string; // Required: Google OAuth Client ID
googleClientSecret?: string; // Optional: For server-side token exchange
aztecRpcUrl?: string; // Optional: Aztec RPC (default: localhost:8080)
redirectUri?: string; // Optional: OAuth callback URL
}Methods
getAuthUrl(): string
const url = manager.getAuthUrl();
window.location.href = url;Returns Google OAuth authorization URL.
exchangeCode(code: string): Promise
const authResult = await manager.exchangeCode(code);
// { idToken: "...", accessToken?: "...", ... }Exchanges OAuth code for JWT and tokens.
createAccount(authResult: AuthResult): Promise
const account = await manager.createAccount(authResult);
// { address: "0x...", accountId: Field, sessionOwner: "0x...", txHash: "0x..." }Creates new account on Aztec.
accountExistsForIdentity(authResult: AuthResult): Promise<AztecAddress | null>
const address = await manager.accountExistsForIdentity(authResult);
if (address) {
// Account found, can recover
}Checks if account exists for the given identity.
recoverAccount(authResult: AuthResult, address: AztecAddress): Promise
const account = await manager.recoverAccount(authResult, existingAddress);Recovers existing account by setting new session owner.
Framework Integration
React
import { useEffect, useState } from 'react';
import { AccountManager } from 'azkey-sdk';
function GoogleSignIn() {
const [manager] = useState(
() => new AccountManager({ googleClientId: 'your-id' })
);
const handleSignIn = () => {
window.location.href = manager.getAuthUrl();
};
return (
<button onClick={handleSignIn}>
Sign in with Google
</button>
);
}Vue
<script setup>
import { ref } from 'vue';
import { AccountManager } from 'azkey-sdk';
const manager = new AccountManager({ googleClientId: 'your-id' });
const handleSignIn = () => {
window.location.href = manager.getAuthUrl();
};
</script>
<template>
<button @click="handleSignIn">Sign in with Google</button>
</template>Svelte
<script>
import { onMount } from 'svelte';
import { AccountManager } from 'azkey-sdk';
let manager;
onMount(() => {
manager = new AccountManager({ googleClientId: 'your-id' });
});
const handleSignIn = () => {
window.location.href = manager.getAuthUrl();
};
</script>
<button on:click={handleSignIn}>Sign in with Google</button>Next.js / SvelteKit
For server-side token exchange:
// In server route
import { AccountManager } from 'azkey-sdk';
const manager = new AccountManager({
googleClientId: process.env.GOOGLE_CLIENT_ID!,
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET!,
aztecRpcUrl: process.env.AZTEC_RPC_URL
});
export async function POST(request) {
const { code } = await request.json();
const authResult = await manager.exchangeCode(code);
// ... create account
return Response.json(authResult);
}Error Handling
try {
const authResult = await manager.exchangeCode(code);
} catch (error) {
if (error.message.includes('invalid_grant')) {
// Code expired or already used
} else if (error.message.includes('invalid_client')) {
// Client ID/Secret incorrect
} else if (error.message.includes('network')) {
// Network error
}
}Best Practices
1. Secure Token Storage
// Don't store sensitive tokens in localStorage
// Use secure HTTP-only cookies if possible
// For demo: sessionStorage (cleared on tab close)
sessionStorage.setItem('session_owner', account.sessionOwner);
// Don't do this:
// localStorage.setItem('google_token', authResult.idToken);2. Error Handling
try {
const account = await manager.createAccount(authResult);
} catch (error) {
console.error('Account creation failed:', error.message);
// Show user-friendly error message
}3. Account Recovery Flow
const authResult = await manager.exchangeCode(code);
// Check if account exists
const existing = await manager.accountExistsForIdentity(authResult);
if (existing) {
// Recover existing account
const account = await manager.recoverAccount(authResult, existing);
} else {
// Create new account
const account = await manager.createAccount(authResult);
}4. Session Management
// After account creation, store ephemeral key securely
const account = await manager.createAccount(authResult);
// Sign transactions with session owner
const tx = /* ... */;
const signature = await signWithSessionOwner(tx, account.sessionOwner);Testing
# Unit tests
pnpm test:unit
# Integration tests (requires Aztec sandbox)
RUN_INTEGRATION_TESTS=true pnpm test:integration
# All tests
pnpm testExamples
Full examples available in GitHub:
- React integration
- Vue integration
- Next.js integration
- Plain JavaScript
Environment Variables
# Required
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
# Optional
GOOGLE_CLIENT_SECRET=your-client-secret
AZTEC_RPC_URL=https://aztec-testnet.example.comTroubleshooting
"Client not initialized"
Ensure AccountManager is initialized before calling methods:
const manager = new AccountManager({ googleClientId: '...' });
// Then use manager"Invalid authorization code"
- Code may have expired (valid for ~10 minutes)
- Code may have already been used
- Redirect URI may not match
"Contract deployment failed"
- Aztec RPC may be unreachable
- Account may already exist
- Network gas price too low
"Session owner not working"
- Ensure you're using the returned session owner from account creation
- Session owner must be authorized in the account contract
Contributing
Found an issue? Open an issue
License
MIT - See LICENSE
