@shogun-sdk/accounts-react
v1.0.25
Published
Shogun React components and hooks for Turnkey (Passkey/Telegram) authentication with Telegram/Turnkey OIDC, etc.
Downloads
11
Readme
@shogun-sdk/accounts-react
React components and hooks for Turnkey authentication - passkeys, OAuth, and wallet management for React apps.
Quick Start
1. Install the Package
Choose your preferred package manager:
npm
npm install @shogun-sdk/accounts-reactpnpm
pnpm add @shogun-sdk/accounts-reactyarn
yarn add @shogun-sdk/accounts-react2. Setup Authentication Providers and Use Components
Set up the providers and create a login component:
import React from 'react';
import {
TurnkeyAuthProvider,
useTurnkeyAuth,
UniversalPasskeyConnectModal,
TurnkeyAccountProvider,
usePasskeyModal,
useSidebar,
} from '@shogun-sdk/accounts-react';
import { Button } from '@shogun-sdk/ui-kit';
import { getTurnkeyConfig } from '@shogun-sdk/accounts';
import { TurnkeyProvider } from '@turnkey/sdk-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function LoginComponent() {
const { state, logout } = useTurnkeyAuth();
const { setPasskeyModal } = usePasskeyModal();
return (
<div className="p-8 rounded-lg shadow-lg max-w-md mx-auto">
<h2 className="text-2xl font-bold mb-6 text-center">Turnkey React Example</h2>
{state.user ? (
<div className="space-y-4">
<div className="text-center">
Welcome, <span className="font-semibold">{state.user.email}</span>!
</div>
<Button onClick={logout} className="w-full">
Logout
</Button>
</div>
) : (
<Button
onClick={() => setPasskeyModal(true)}
className="w-full"
>
Login with Universal Account
</Button>
)}
</div>
);
}
function App() {
const { setPasskeyModal } = usePasskeyModal();
const { setIsSidebarOpen } = useSidebar();
const turnkeyConfig = getTurnkeyConfig(
process.env.REACT_APP_BASE_URL || 'https://api.turnkey.com',
process.env.REACT_APP_ORGANIZATION_ID || 'your-turnkey-org-id',
process.env.REACT_APP_RP_ID || 'your-app-domain',
);
return (
<div className="min-h-screen bg-gray-50 py-12">
<TurnkeyProvider config={turnkeyConfig}>
<QueryClientProvider client={queryClient}>
<TurnkeyAuthProvider
setPasskeyModal={setPasskeyModal}
setIsSidebarOpen={setIsSidebarOpen}
errorHandler={console.error}
externalAuthDomain={process.env.REACT_APP_EXTERNAL_AUTH_DOMAIN || 'https://example.com'}
showError={console.error}
turnkeyConfig={turnkeyConfig}
>
<TurnkeyAccountProvider errorHandler={console.error}>
<LoginComponent />
<UniversalPasskeyConnectModal closeIcon={<CloseIcon />} swapLogo={<Logo />} />
</TurnkeyAccountProvider>
</TurnkeyAuthProvider>
</QueryClientProvider>
</TurnkeyProvider>
</div>
);
}3. Configure Environment Variables and Explore Features
Set up your environment variables and explore all available hooks and components below:
# .env or .env.local
REACT_APP_BASE_URL=https://api.turnkey.com
REACT_APP_ORGANIZATION_ID=your-turnkey-organization-id
REACT_APP_RP_ID=localhost # or your domain
REACT_APP_EXTERNAL_AUTH_DOMAIN=https://your-auth-domain.comCheck the API Reference and Component Examples below for all available features.
Features
- 🔐 Passkey Authentication - Seamless passkey login and account creation
- 🔑 OAuth Integration - Support for Telegram and other OAuth providers
- ⚛️ React Context - Centralized authentication state management
- 🎨 UI Components - Pre-built modal components for authentication flows
- 🪝 Custom Hooks - Easy-to-use hooks for authentication and UI control
- 📱 Universal Passkey - Cross-platform passkey support with iframes
- 🔄 Account Recovery - Built-in account recovery mechanisms
- 📝 TypeScript Ready - Full type safety and IntelliSense
Component Examples
Basic Authentication Flow
import { useTurnkeyAuth, usePasskeyModal } from '@shogun-sdk/accounts-react';
import { Button } from '@shogun-sdk/ui-kit';
function AuthComponent() {
const { state, logout, isAuthenticating } = useTurnkeyAuth();
const { setPasskeyModal } = usePasskeyModal();
if (state.loading) {
return <div>Loading...</div>;
}
return (
<div>
{state.user ? (
<div>
<h3>Welcome back!</h3>
<p>Email: {state.user.email}</p>
<p>Username: {state.user.username}</p>
<Button onClick={logout}>Logout</Button>
</div>
) : (
<div>
<h3>Please log in</h3>
<Button
onClick={() => setPasskeyModal(true)}
disabled={isAuthenticating}
>
{isAuthenticating ? 'Authenticating...' : 'Login with Passkey'}
</Button>
</div>
)}
</div>
);
}Custom Authentication Methods
import { useTurnkeyAuth } from '@shogun-sdk/accounts-react';
import { Button } from '@shogun-sdk/ui-kit';
function CustomAuthComponent() {
const {
state,
loginWithPasskey,
loginWithTelegram,
createAccountWithPasskey,
logout,
isAuthenticating
} = useTurnkeyAuth();
const handleCreateAccount = async () => {
try {
const result = await createAccountWithPasskey('john_doe', '[email protected]');
if (result.status) {
console.log('Account created successfully!');
} else {
console.error('Account creation failed:', result.message);
}
} catch (error) {
console.error('Error creating account:', error);
}
};
const handleTelegramLogin = async (telegramUser) => {
try {
await loginWithTelegram(telegramUser);
console.log('Telegram login successful!');
} catch (error) {
console.error('Telegram login failed:', error);
}
};
return (
<div className="space-y-4">
{state.user ? (
<div>
<p>Welcome, {state.user.username}!</p>
<Button onClick={logout}>Logout</Button>
</div>
) : (
<div className="space-y-2">
<Button
onClick={loginWithPasskey}
disabled={isAuthenticating}
className="w-full"
>
Login with Passkey
</Button>
<Button
onClick={handleCreateAccount}
disabled={isAuthenticating}
variant="outline"
className="w-full"
>
Create New Account
</Button>
</div>
)}
</div>
);
}UI State Management
import { useControls } from '@shogun-sdk/accounts-react';
import { Button, Dialog, DialogContent } from '@shogun-sdk/ui-kit';
function UIControlsExample() {
const {
isSidebarOpen,
passkeyModalOpen,
isRecoveryMode,
setPasskeyModal,
setIsSidebarOpen,
toggleSidebar,
setRecoveryMode
} = useControls();
return (
<div className="space-y-4">
<div className="flex space-x-2">
<Button onClick={toggleSidebar}>
{isSidebarOpen ? 'Close' : 'Open'} Sidebar
</Button>
<Button onClick={() => setPasskeyModal(true)}>
Open Passkey Modal
</Button>
<Button onClick={() => setRecoveryMode(!isRecoveryMode)}>
{isRecoveryMode ? 'Exit' : 'Enter'} Recovery Mode
</Button>
</div>
{/* Conditional UI based on state */}
{isSidebarOpen && (
<div className="bg-gray-100 p-4 rounded">
<h3>Sidebar Content</h3>
<p>Sidebar is open!</p>
</div>
)}
{isRecoveryMode && (
<div className="bg-yellow-100 p-4 rounded border-yellow-400 border">
<h3>Recovery Mode Active</h3>
<p>Help users recover their accounts</p>
</div>
)}
</div>
);
}Complete Application Setup
import React from 'react';
import {
TurnkeyAuthProvider,
TurnkeyAccountProvider,
UniversalPasskeyConnectModal,
usePasskeyModal,
useSidebar,
} from '@shogun-sdk/accounts-react';
import { getTurnkeyConfig } from '@shogun-sdk/accounts';
import { TurnkeyProvider } from '@turnkey/sdk-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function AppWithProviders() {
const { setPasskeyModal } = usePasskeyModal();
const { setIsSidebarOpen } = useSidebar();
const turnkeyConfig = getTurnkeyConfig(
process.env.REACT_APP_BASE_URL!,
process.env.REACT_APP_ORGANIZATION_ID!,
process.env.REACT_APP_RP_ID!
);
const errorHandler = (error: Error) => {
console.error('Turnkey error:', error);
// Send to your error tracking service
};
const showError = (error: Error | string) => {
const message = typeof error === 'string' ? error : error.message;
// Show error to user (toast, modal, etc.)
console.error('User error:', message);
};
return (
<TurnkeyProvider config={turnkeyConfig}>
<QueryClientProvider client={queryClient}>
<TurnkeyAuthProvider
setPasskeyModal={setPasskeyModal}
setIsSidebarOpen={setIsSidebarOpen}
errorHandler={errorHandler}
showError={showError}
turnkeyConfig={turnkeyConfig}
externalAuthDomain={process.env.REACT_APP_EXTERNAL_AUTH_DOMAIN}
>
<TurnkeyAccountProvider errorHandler={errorHandler}>
{/* Your app components */}
<YourAppContent />
{/* Authentication modal */}
<UniversalPasskeyConnectModal
closeIcon={<CloseIcon />}
swapLogo={<YourLogo />}
/>
</TurnkeyAccountProvider>
</TurnkeyAuthProvider>
</QueryClientProvider>
</TurnkeyProvider>
);
}API Reference
Providers
TurnkeyAuthProvider
Main authentication provider that manages auth state and provides context.
Props:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| children | React.ReactNode | ✅ | Your app components |
| setPasskeyModal | (value: boolean) => void | ✅ | Function to control passkey modal |
| setIsSidebarOpen | (value: boolean) => void | ✅ | Function to control sidebar state |
| errorHandler | (error: Error) => void \| Promise<void> | ✅ | Error handling function |
| turnkeyConfig | ITurnkeyConfig | ✅ | Turnkey SDK configuration |
| showError | (error: Error \| string) => void | ✅ | Function to display errors |
| externalAuthDomain | string | ❌ | External authentication domain |
| oidcDomainUrl | string | ❌ | OIDC domain for OAuth flows |
| getEncryptedValue | (subOrgId: string) => Promise<string> | ❌ | Get encrypted values |
TurnkeyAccountProvider
Secondary provider for account-specific functionality.
Props:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| children | React.ReactNode | ✅ | Child components |
| errorHandler | (error: Error) => void | ✅ | Error handling function |
Hooks
useTurnkeyAuth
Main authentication hook providing auth state and methods.
Returns:
| Property | Type | Description |
|----------|------|-------------|
| state | TurnkeyAuthState | Current authentication state |
| loginWithTelegram | (user: TelegramUser) => Promise<void> | Login with Telegram OAuth |
| loginWithPasskey | () => Promise<void> | Login with passkey |
| loginWithPasskeyIframe | () => Promise<void> | Login with passkey in iframe |
| createAccountWithPasskey | (userName: string, userEmail: string) => Promise<{status?: boolean; message?: string;}> | Create account with passkey |
| fetchUser | (isSessionCheck?: boolean, logoutClear?: () => void) => Promise<void> | Fetch current user |
| logout | () => Promise<void> | Logout current user |
| getActiveTurnkeyClient | (chainId: number, signWith?: string) => Promise<TurnkeyBrowserClient> | Get Turnkey client |
| isAuthenticating | boolean | Whether authentication is in progress |
| externalSubOrgId | string | External sub-organization ID |
| authDomainUrl | string | Authentication domain URL |
| selectCurrentPasskey | () => Promise<void> | Select current passkey |
useControls
Hook for managing UI state and controls.
Returns:
| Property | Type | Description |
|----------|------|-------------|
| isSidebarOpen | boolean | Sidebar open state |
| passkeyModalOpen | boolean | Passkey modal open state |
| isRecoveryMode | boolean | Recovery mode state |
| isConnectWalletModalOpen | boolean | Connect wallet modal state |
| showHiddenTokenTab | boolean | Hidden token tab visibility |
| offInteraction | boolean | Interaction disabled state |
| setPasskeyModal | (status: boolean) => void | Set passkey modal state |
| setIsSidebarOpen | (status: boolean) => void | Set sidebar state |
| setRecoveryMode | (status: boolean) => void | Set recovery mode |
| setConnectWalletModal | (status: boolean) => void | Set connect wallet modal |
| toggleSidebar | () => void | Toggle sidebar |
| toggleConnectWalletModal | () => void | Toggle connect wallet modal |
| toggleHiddenTokenTab | () => void | Toggle hidden token tab |
| setOffInteractionMode | (status: boolean) => void | Set interaction mode |
usePasskeyModal
Convenience hook for passkey modal control.
Returns:
| Property | Type | Description |
|----------|------|-------------|
| passkeyModalOpen | boolean | Modal open state |
| setPasskeyModal | (status: boolean) => void | Set modal state |
useSidebar
Convenience hook for sidebar control.
Returns:
| Property | Type | Description |
|----------|------|-------------|
| isSidebarOpen | boolean | Sidebar open state |
| setIsSidebarOpen | (status: boolean) => void | Set sidebar state |
| toggleSidebar | () => void | Toggle sidebar |
Components
UniversalPasskeyConnectModal
Modal component for passkey authentication flows.
Props:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| closeIcon | React.ReactNode | ❌ | Custom close icon |
| swapLogo | React.ReactNode | ❌ | Custom logo |
<UniversalPasskeyConnectModal
closeIcon={<X size={24} />}
swapLogo={<YourLogo />}
/>TermsAndPrivacy
Component displaying terms and privacy information.
import { TermsAndPrivacy } from '@shogun-sdk/accounts-react';
<TermsAndPrivacy />Authentication State
The authentication state object includes:
interface TurnkeyAuthState {
user: User | null;
loading: boolean;
error: string | null;
userLoading: boolean;
accountCreating: boolean;
isAuthenticated: boolean;
// ... other state properties
}
interface User {
email: string;
username: string;
id: string;
// ... other user properties
}Environment Variables
React (.env or .env.local)
# Turnkey Configuration
REACT_APP_BASE_URL=https://api.turnkey.com
REACT_APP_ORGANIZATION_ID=your-turnkey-organization-id
REACT_APP_RP_ID=localhost # or your domain like myapp.com
# Optional: External Authentication
REACT_APP_EXTERNAL_AUTH_DOMAIN=https://your-auth-domain.com
REACT_APP_OIDC_DOMAIN_URL=https://oidc.your-domain.comNext.js (.env.local)
# For client-side access (Next.js requires NEXT_PUBLIC_ prefix)
NEXT_PUBLIC_TURNKEY_API_URL=https://api.turnkey.com
NEXT_PUBLIC_TURNKEY_ORG_ID=your-organization-id
NEXT_PUBLIC_TURNKEY_RP_ID=your-app-domain.com
NEXT_PUBLIC_EXTERNAL_AUTH_DOMAIN=https://your-auth-domain.comVite (.env)
# For Vite (requires VITE_ prefix)
VITE_TURNKEY_API_URL=https://api.turnkey.com
VITE_TURNKEY_ORG_ID=your-organization-id
VITE_TURNKEY_RP_ID=your-app-domain.com
VITE_EXTERNAL_AUTH_DOMAIN=https://your-auth-domain.comError Handling
Comprehensive Error Handling
const errorHandler = async (error: Error) => {
console.error('Authentication error:', error);
// Log to external service
if (process.env.NODE_ENV === 'production') {
await logToService(error);
}
// Handle specific error types
if (error.message.includes('passkey')) {
showError('Passkey authentication failed. Please try again.');
} else if (error.message.includes('network')) {
showError('Network error. Please check your connection.');
} else {
showError('Authentication failed. Please try again.');
}
};
const showError = (error: Error | string) => {
const message = typeof error === 'string' ? error : error.message;
// Show toast notification
toast.error(message);
// Or update UI state
setErrorMessage(message);
};Error Recovery
function ErrorBoundaryExample() {
const { state, fetchUser } = useTurnkeyAuth();
const retryAuth = async () => {
try {
await fetchUser();
} catch (error) {
console.error('Retry failed:', error);
}
};
if (state.error) {
return (
<div className="error-state">
<h3>Authentication Error</h3>
<p>{state.error}</p>
<Button onClick={retryAuth}>Retry</Button>
</div>
);
}
return <YourAppContent />;
}Common Patterns
Protecting Routes
import { useTurnkeyAuth } from '@shogun-sdk/accounts-react';
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { state } = useTurnkeyAuth();
if (state.loading) {
return <div>Loading...</div>;
}
if (!state.user) {
return <LoginComponent />;
}
return <>{children}</>;
}
// Usage
<ProtectedRoute>
<DashboardComponent />
</ProtectedRoute>Conditional Rendering
function ConditionalAuth() {
const { state } = useTurnkeyAuth();
const { setPasskeyModal } = usePasskeyModal();
return (
<div>
{state.user ? (
<UserDashboard user={state.user} />
) : (
<div>
<WelcomeMessage />
<Button onClick={() => setPasskeyModal(true)}>
Get Started
</Button>
</div>
)}
</div>
);
}Loading States
function LoadingStates() {
const { state, isAuthenticating } = useTurnkeyAuth();
return (
<div>
{state.loading && <div>Initializing...</div>}
{state.userLoading && <div>Loading user...</div>}
{state.accountCreating && <div>Creating account...</div>}
{isAuthenticating && <div>Authenticating...</div>}
</div>
);
}TypeScript Support
The package is fully typed with comprehensive TypeScript definitions:
import type {
TurnkeyAuthState,
TurnkeyAuthContextType,
TurnkeyAuthProviderProps,
User,
TelegramUser
} from '@shogun-sdk/accounts-react';
// Extend the user type if needed
interface ExtendedUser extends User {
customField: string;
}
// Custom hook with extended typing
const useExtendedAuth = (): TurnkeyAuthContextType<ExtendedUser> => {
// Your implementation
};Dependencies
Key dependencies include:
- @turnkey/sdk-react - Core Turnkey React SDK
- @shogun-sdk/accounts - Core Turnkey integration
- @shogun-sdk/ui-kit - UI components
- @shogun-sdk/money-legos - Blockchain utilities
- framer-motion - Smooth animations
- zustand - State management
- react - React framework (^18.0.0)
Next.js Integration
App Router (app/layout.tsx)
'use client';
import { TurnkeyProvider } from '@turnkey/sdk-react';
import { TurnkeyAuthProvider } from '@shogun-sdk/accounts-react';
import { getTurnkeyConfig } from '@shogun-sdk/accounts';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const turnkeyConfig = getTurnkeyConfig(
process.env.NEXT_PUBLIC_TURNKEY_API_URL!,
process.env.NEXT_PUBLIC_TURNKEY_ORG_ID!,
process.env.NEXT_PUBLIC_TURNKEY_RP_ID!
);
return (
<html lang="en">
<body>
<TurnkeyProvider config={turnkeyConfig}>
<TurnkeyAuthProvider /* props */>
{children}
</TurnkeyAuthProvider>
</TurnkeyProvider>
</body>
</html>
);
}Pages Router (pages/_app.tsx)
import type { AppProps } from 'next/app';
import { TurnkeyProvider } from '@turnkey/sdk-react';
import { TurnkeyAuthProvider } from '@shogun-sdk/accounts-react';
import { getTurnkeyConfig } from '@shogun-sdk/accounts';
export default function App({ Component, pageProps }: AppProps) {
const turnkeyConfig = getTurnkeyConfig(
process.env.NEXT_PUBLIC_TURNKEY_API_URL!,
process.env.NEXT_PUBLIC_TURNKEY_ORG_ID!,
process.env.NEXT_PUBLIC_TURNKEY_RP_ID!
);
return (
<TurnkeyProvider config={turnkeyConfig}>
<TurnkeyAuthProvider /* props */>
<Component {...pageProps} />
</TurnkeyAuthProvider>
</TurnkeyProvider>
);
}Support
Requirements
- React 18+: Required for concurrent features
- Turnkey Account: Visit Turnkey to create an account
- HTTPS Environment: Required for WebAuthn/passkey functionality
- Modern Browser: Support for WebAuthn APIs
License
ISC
