A comprehensive authentication hook for GunDB applications that provides automatic key generation, storage management, and authentication state tracking.
The useAuth hook provides a complete authentication solution for GunDB applications, managing user keys, authentication state, and secure storage automatically. It integrates seamlessly with the AuthProvider component to deliver a robust authentication system.
useAuth(): AuthContextTypeinterface AuthContextType {
gun: IGunChainReference; // Gun instance
user: IGunUserReference; // Authenticated user reference
login: (keys?: KeyPair | string) => void; // Login function
logout: (onLoggedOut?: () => void) => void; // Logout function
sea: any; // SEA instance
appKeys: KeyPair | string | undefined; // Current keys
isLoggedIn: boolean; // Authentication status
newGunInstance: (opts?: GunOptions) => IGunChainReference; // Create new Gun instance
}import { AuthProvider, useAuth } from '@altrx/gundb-react-hooks';
import Gun from 'gun';
import 'gun/sea';
// Wrap your app with AuthProvider
function App() {
return (
<AuthProvider
Gun={Gun}
sea={Gun.SEA}
storage={localStorage}
gunOpts={{ peers: ['http://localhost:8765/gun'] }}
>
<AuthenticatedApp />
</AuthProvider>
);
}
// Use authentication in components
function AuthenticatedApp() {
const {
user,
login,
logout,
isLoggedIn,
appKeys,
gun
} = useAuth();
return (
<div>
{isLoggedIn ? (
<div>
<p>Welcome! You are authenticated.</p>
<p>Your public key: {appKeys?.pub}</p>
<button onClick={() => logout()}>Logout</button>
</div>
) : (
<div>
<p>Please log in</p>
<button onClick={() => login()}>Login with new keys</button>
</div>
)}
</div>
);
}// For React Native with AsyncStorage
import AsyncStorage from '@react-native-async-storage/async-storage';
const asyncStorage = {
getItem: async (key: string) => {
const value = await AsyncStorage.getItem(key);
return value;
},
setItem: async (key: string, data: string) => {
await AsyncStorage.setItem(key, data);
},
removeItem: async (key: string) => {
await AsyncStorage.removeItem(key);
}
};
<AuthProvider storage={asyncStorage} ... />function LoginForm() {
const { login } = useAuth();
const [keyInput, setKeyInput] = useState('');
const handleLogin = () => {
try {
const keys = JSON.parse(keyInput);
login(keys);
} catch (error) {
console.error('Invalid key format:', error);
}
};
return (
<div>
<textarea
value={keyInput}
onChange={(e) => setKeyInput(e.target.value)}
placeholder="Paste your keys here..."
/>
<button onClick={handleLogin}>Login</button>
</div>
);
}function KeyManagement() {
const { appKeys, isLoggedIn } = useAuth();
const exportKeys = () => {
if (appKeys) {
const keyString = JSON.stringify(appKeys, null, 2);
navigator.clipboard.writeText(keyString);
alert('Keys copied to clipboard');
}
};
return (
<div>
{isLoggedIn && (
<button onClick={exportKeys}>
Export Keys
</button>
)}
</div>
);
}function LogoutButton() {
const { logout } = useAuth();
const handleLogout = () => {
logout(() => {
// Cleanup after logout
console.log('User logged out successfully');
// Redirect or update UI
window.location.href = '/login';
});
};
return <button onClick={handleLogout}>Logout</button>;
}function UserProfile() {
const { user, isLoggedIn } = useAuth();
const { fields, put, error } = useGunState(
user?.get('profile'),
{ appKeys: user?.is }
);
if (!isLoggedIn) return <div>Please log in</div>;
return (
<div>
<input
value={fields.name || ''}
onChange={(e) => put({ name: e.target.value })}
/>
{error && <div>Error: {error.err}</div>}
</div>
);
}function UserPosts() {
const { user, isLoggedIn } = useAuth();
const { items, addToSet, error } = useGunCollectionState(
user?.get('posts'),
{ appKeys: user?.is }
);
if (!isLoggedIn) return <div>Please log in</div>;
return (
<div>
{items.map(post => (
<div key={post.nodeID}>{post.title}</div>
))}
<button onClick={() => addToSet({ title: 'New Post' })}>
Add Post
</button>
{error && <div>Error: {error.err}</div>}
</div>
);
}The authentication system includes comprehensive error handling:
function AuthStatus() {
const { isLoggedIn, login } = useAuth();
const handleLogin = async () => {
try {
await login();
} catch (error) {
console.error('Login failed:', error);
// Handle authentication errors
}
};
return (
<div>
<p>Status: {isLoggedIn ? 'Authenticated' : 'Not authenticated'}</p>
<button onClick={handleLogin}>Login</button>
</div>
);
}// Manual authentication management
const [keys, setKeys] = useState(null);
const [user, setUser] = useState(null);
const [isLoggedIn, setIsLoggedIn] = useState(false);
// Manual key storage
useEffect(() => {
const storedKeys = localStorage.getItem('keys');
if (storedKeys) {
setKeys(JSON.parse(storedKeys));
}
}, []);// Automatic authentication with AuthProvider
function App() {
return (
<AuthProvider Gun={Gun} sea={Gun.SEA} storage={localStorage} gunOpts={opts}>
<AuthenticatedApp />
</AuthProvider>
);
}
// Simple hook usage
const { user, login, logout, isLoggedIn, appKeys } = useAuth();- Always wrap your app with
AuthProviderat the root level - Use meaningful storage keys when deploying multiple apps
- Handle storage failures gracefully in your storage implementation
- Secure key storage in production environments
- Validate imported keys before using them
- Provide clear user feedback during authentication processes
All authentication features are fully typed:
import type {
KeyPair,
AuthContextType,
Storage,
} from '@altrx/gundb-react-hooks';
const customStorage: Storage = {
getItem: (key: string) => localStorage.getItem(key),
setItem: (key: string, data: string) => localStorage.setItem(key, data),
removeItem: (key: string) => localStorage.removeItem(key),
};function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isLoggedIn } = useAuth();
if (!isLoggedIn) {
return <LoginForm />;
}
return <>{children}</>;
}function AutoBackup() {
const { appKeys, isLoggedIn } = useAuth();
useEffect(() => {
if (isLoggedIn && appKeys) {
// Automatically backup keys to secure storage
backupKeysToSecureStorage(appKeys);
}
}, [isLoggedIn, appKeys]);
return null;
}