@glitch_protocol/auth-react
v0.2.0
Published
React hooks and components for glitch_protocol
Maintainers
Readme
@glitch_protocol/auth-react
React hooks and components for glitch_protocol. Provides a context provider, session management hooks, and pre-built UI components for displaying active sessions.
Install
npm install @glitch_protocol/auth-react @glitch_protocol/auth-client react react-dom socket.io-client zustandSetup
1. Create auth client and store (see @glitch_protocol/auth-client)
// lib/auth.ts
import { createglitch_protocolClient, createAuthStore, createSocketClient } from "@glitch_protocol/auth-client";
let getToken = () => null as string | null;
let onRefreshed = (t: string) => {};
let onCleared = () => {};
export const client = createglitch_protocolClient({
baseUrl: "http://localhost:4000",
getAccessToken: () => getToken(),
onTokenRefreshed: (t) => onRefreshed(t),
onAuthCleared: () => onCleared(),
});
export const useAuthStore = createAuthStore({ client });
getToken = () => useAuthStore.getState().accessToken;
onRefreshed = (t) => useAuthStore.getState().setAccessToken(t);
onCleared = () => useAuthStore.getState().clearAuth();
export const socketClient = createSocketClient({
serverUrl: "http://localhost:4000",
getAccessToken: () => useAuthStore.getState().accessToken,
});2. Wrap your app with glitch_protocolProvider
// app.tsx
import { glitch_protocolProvider } from "@glitch_protocol/auth-react";
import { useAuthStore, socketClient } from "./lib/auth";
export default function App() {
return (
<glitch_protocolProvider store={useAuthStore} socketClient={socketClient}>
<Dashboard />
</glitch_protocolProvider>
);
}Hooks
useAuth
Access auth state and operations.
function useAuth(): {
user: AuthUser | null;
accessToken: string | null;
isLoading: boolean;
isInitialized: boolean;
login: (email: string, password: string) => Promise<{ success: boolean; error?: string }>;
register: (name: string, email: string, password: string) => Promise<{ success: boolean; error?: string }>;
logout: () => Promise<void>;
}Example:
function Dashboard() {
const { user, isLoading, isInitialized, logout } = useAuth();
if (!isInitialized) return <Spinner />;
if (!user) return <LoginForm />;
return (
<div>
<p>Welcome, {user.name}</p>
<button onClick={logout}>Sign out</button>
</div>
);
}login / register:
Both return { success: true } on success or { success: false, error: "message" } on failure. Automatically set auth state on success.
function LoginForm() {
const { login } = useAuth();
const handleSubmit = async (email: string, password: string) => {
const result = await login(email, password);
if (result.success) {
// Redirect to dashboard (done by state change)
} else {
toast.error(result.error);
}
};
return <form onSubmit={handleSubmit}>...</form>;
}useSessions
Access active sessions and termination.
function useSessions(): {
sessions: SessionInfo[];
terminateSession: (sessionId: string) => Promise<void>;
terminateOtherSessions: () => Promise<void>;
}Example:
function SessionManager() {
const { sessions, terminateSession, terminateOtherSessions } = useSessions();
return (
<div>
<h2>Your Devices</h2>
{sessions.map((session) => (
<div key={session.id}>
<p>{session.browser} on {session.os}</p>
<p>{session.ipAddress}</p>
<p>{new Date(session.lastActivity).toLocaleString()}</p>
<button onClick={() => terminateSession(session.id)}>
Sign out
</button>
</div>
))}
<button onClick={terminateOtherSessions}>
Sign out all other devices
</button>
</div>
);
}useSocket
Access the Socket.IO client for custom event listeners.
function useSocket(): {
socket: Socket | null;
isConnected: boolean;
getSocket: () => Socket | null;
}Example:
function ConnectionStatus() {
const { isConnected, socket } = useSocket();
useEffect(() => {
if (!socket) return;
socket.on("custom:event", (data) => {
console.log("Received:", data);
});
return () => socket.off("custom:event");
}, [socket]);
return <span>{isConnected ? "🟢 Online" : "🔴 Offline"}</span>;
}Components
SessionCard
Displays a single session with termination button.
interface SessionCardProps {
session: SessionInfo;
onTerminate?: (sessionId: string) => Promise<void>;
isCurrent?: boolean;
}
export function Dashboard() {
const { sessions, terminateSession } = useSessions();
return (
<>
{sessions.map((session) => (
<SessionCard
key={session.id}
session={session}
isCurrent={session.id === currentSessionId}
onTerminate={terminateSession}
/>
))}
</>
);
}Rendered:
┌─ Chrome on Windows ──────────────────┐
│ 192.168.1.100 │
│ Last activity: 2 minutes ago │
│ [Signed in 3 days ago] [Sign out] │
└──────────────────────────────────────┘SessionManager
Pre-built session management UI with list and bulk actions.
export function SettingsPage() {
return (
<div>
<h1>Settings</h1>
<SessionManager />
</div>
);
}Features:
- Lists all active sessions
- Marks current session as "This device"
- Button to terminate each session individually
- Button to "Sign out all other devices"
- Real-time updates when new session created or terminated
Real-Time Events
The provider automatically connects to Socket.IO and listens for events:
session:new— New login detected on another devicesession:terminated— A session was terminatedsession:list-updated— Session list changed (e.g., activity update)
State is automatically updated when these events arrive. No manual handling needed.
Custom listeners:
function MyComponent() {
const { socket } = useSocket();
useEffect(() => {
if (!socket) return;
socket.on("session:new", (session) => {
toast.info(`New login from ${session.browser}`);
});
return () => socket.off("session:new");
}, [socket]);
return null;
}Example: Complete App
// app.tsx
import { useEffect } from "react";
import { glitch_protocolProvider, useAuth, useSessions } from "@glitch_protocol/auth-react";
import { useAuthStore, socketClient } from "./lib/auth";
function App() {
return (
<glitch_protocolProvider store={useAuthStore} socketClient={socketClient}>
<Layout />
</glitch_protocolProvider>
);
}
function Layout() {
const initialize = useAuthStore((s) => s.initialize);
const isInitialized = useAuthStore((s) => s.isInitialized);
useEffect(() => {
initialize();
}, [initialize]);
if (!isInitialized) return <Spinner />;
return (
<div>
<Header />
<Router>
<Route path="/" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Router>
</div>
);
}
function Header() {
const { user, logout } = useAuth();
return (
<nav>
<div>Hello, {user?.name}</div>
<button onClick={logout}>Sign out</button>
</nav>
);
}
function Dashboard() {
const { user } = useAuth();
const { sessions } = useSessions();
return (
<div>
<h1>Dashboard</h1>
<p>You have {sessions.length} active session(s)</p>
{sessions.map((session) => (
<SessionCard key={session.id} session={session} />
))}
</div>
);
}
function Settings() {
return (
<div>
<h1>Settings</h1>
<SessionManager />
</div>
);
}
export default App;Peer Dependencies
react: >=18.0.0— React libraryreact-dom: >=18.0.0— React DOM library@glitch_protocol/auth-client: ^0.1.0— Browser SDKsocket.io-client: ^4.8.0— Real-time eventszustand: ^5.0.0— State management
Node Version
ESM-only. Requires Node.js >=18.
