UNPKG

@narangcia-oss/cryptic-auth-client-react

Version:

React hooks and components for cryptic-auth authentication with seamless OAuth2 integration

653 lines (520 loc) 13.3 kB
# cryptic-auth/react > **React hooks and components for cryptic-auth authentication with seamless OAuth2 integration and intuitive developer experience.** --- ## Overview `@narangcia-oss/cryptic-auth-client-react` provides a complete React solution for integrating with cryptic-auth servers. It offers an intuitive, hook-based API with pre-built components for common authentication flows. - **🎣 React Hooks**: Simple hooks for authentication state management - **🔐 Auth Context**: Global authentication state with React Context - **🚀 OAuth2 Support**: One-click OAuth login with popular providers - **🛡️ Route Protection**: Easy route guards and authentication checks - **📱 Components**: Pre-built login forms and OAuth buttons - **🎨 Customizable**: Flexible styling and behavior customization - **📝 TypeScript**: Full TypeScript support with comprehensive types --- ## Installation ```bash npm install @narangcia-oss/cryptic-auth-client-react # or yarn add @narangcia-oss/cryptic-auth-client-react # or pnpm add @narangcia-oss/cryptic-auth-client-react ``` **Peer Dependencies:** - `react ^16.8.0 || ^17.0.0 || ^18.0.0` - `react-dom ^16.8.0 || ^17.0.0 || ^18.0.0` --- ## Quick Start ### 1. Setup AuthProvider Wrap your app with the `AuthProvider`: ```tsx import React from 'react'; import { AuthProvider } from '@narangcia-oss/cryptic-auth-client-react'; function App() { return ( <AuthProvider config={{ baseURL: 'https://your-cryptic-auth-server.com/api', tokenStorage: 'localStorage', // or 'sessionStorage', 'memory' }} > <YourAppContent /> </AuthProvider> ); } ``` ### 2. Use Authentication in Components ```tsx import React from 'react'; import { useAuth, useUser, AuthGuard } from '@narangcia-oss/cryptic-auth-client-react'; function Dashboard() { const { logout } = useAuth(); const { user, displayName, email } = useUser(); return ( <AuthGuard fallback={<div>Please log in</div>}> <div> <h1>Welcome, {displayName}!</h1> {email && <p>Email: {email}</p>} <button onClick={logout}>Logout</button> </div> </AuthGuard> ); } ``` ### 3. Add Login with Pre-built Components ```tsx import React from 'react'; import { LoginForm, OAuthButton } from '@narangcia-oss/cryptic-auth-client-react'; function LoginPage() { return ( <div> <h1>Login</h1> {/* Traditional login form */} <LoginForm onSuccess={() => console.log('Logged in!')} onError={(error) => console.error('Login failed:', error)} /> <div> <p>Or continue with:</p> <OAuthButton provider="google">Continue with Google</OAuthButton> <OAuthButton provider="github">Continue with GitHub</OAuthButton> <OAuthButton provider="discord">Continue with Discord</OAuthButton> </div> </div> ); } ``` --- ## Core Hooks ### `useAuth()` Main authentication hook with full state and actions: ```tsx import { useAuth } from '@narangcia-oss/cryptic-auth-client-react'; function MyComponent() { const { // State isAuthenticated, isLoading, user, tokens, error, // Actions login, signup, logout, oauthLogin, refreshToken, clearError, } = useAuth(); return ( <div> {isLoading && <div>Loading...</div>} {error && <div>Error: {error}</div>} {isAuthenticated ? ( <div>Welcome back!</div> ) : ( <button onClick={() => login({ username: 'user', password: 'pass' })}> Login </button> )} </div> ); } ``` ### `useUser()` Hook focused on current user information: ```tsx import { useUser } from '@narangcia-oss/cryptic-auth-client-react'; function UserProfile() { const { user, isAuthenticated, displayName, email, oauthProvider, } = useUser(); if (!isAuthenticated) return <div>Not logged in</div>; return ( <div> <h2>{displayName}</h2> {email && <p>Email: {email}</p>} {oauthProvider && <p>Signed in with {oauthProvider}</p>} </div> ); } ``` ### `useOAuth()` Specialized hook for OAuth flows: ```tsx import { useOAuth } from '@narangcia-oss/cryptic-auth-client-react'; function SocialLogin() { const { login, isLoading, error } = useOAuth(); const handleGoogleLogin = () => { login('google', ['profile', 'email']); }; return ( <div> <button onClick={handleGoogleLogin} disabled={isLoading}> {isLoading ? 'Redirecting...' : 'Login with Google'} </button> {error && <div>Error: {error}</div>} </div> ); } ``` ### `useCredentialAuth()` Hook for username/password authentication: ```tsx import { useCredentialAuth } from '@narangcia-oss/cryptic-auth-client-react'; function LoginForm() { const { login, signup, isLoading, error } = useCredentialAuth(); const [credentials, setCredentials] = useState({ username: '', password: '' }); const handleSubmit = (e) => { e.preventDefault(); login(credentials); }; return ( <form onSubmit={handleSubmit}> {/* form fields */} <button type="submit" disabled={isLoading}> {isLoading ? 'Logging in...' : 'Login'} </button> </form> ); } ``` ### `useAuthGuard()` Hook for protecting routes and components: ```tsx import { useAuthGuard } from '@narangcia-oss/cryptic-auth-client-react'; function ProtectedPage() { const { canAccess, isChecking } = useAuthGuard({ redirectTo: '/login', redirect: true, }); if (isChecking) return <div>Checking authentication...</div>; if (!canAccess) return null; // Will redirect return <div>Protected content</div>; } ``` --- ## Components ### `<AuthGuard>` Conditionally render content based on authentication status: ```tsx import { AuthGuard } from '@narangcia-oss/cryptic-auth-client-react'; function App() { return ( <AuthGuard fallback={<LoginPage />} loading={<div>Loading...</div>} redirect={false} // Set to true to redirect instead of showing fallback redirectTo="/login" > <Dashboard /> </AuthGuard> ); } ``` ### `<OAuthButton>` Pre-styled OAuth login button: ```tsx import { OAuthButton } from '@narangcia-oss/cryptic-auth-client-react'; function LoginOptions() { return ( <div> <OAuthButton provider="google" scopes={['profile', 'email']} className="my-custom-button" onBeforeLogin={() => console.log('Starting OAuth flow')} > Continue with Google </OAuthButton> <OAuthButton provider="github" /> <OAuthButton provider="discord" /> </div> ); } ``` ### `<LoginForm>` Complete login form with validation: ```tsx import { LoginForm } from '@narangcia-oss/cryptic-auth-client-react'; function LoginPage() { return ( <LoginForm onSuccess={() => { console.log('Login successful!'); // Redirect or update UI }} onError={(error) => { console.error('Login failed:', error); // Show error message }} className="my-login-form" submitText="Sign In" showSignupLink={true} /> ); } ``` --- ## OAuth2 Flow Example Complete OAuth2 implementation: ```tsx import React from 'react'; import { AuthProvider, useAuth, OAuthButton, AuthGuard, } from '@narangcia-oss/cryptic-auth-client-react'; // App wrapper with AuthProvider function App() { return ( <AuthProvider config={{ baseURL: 'https://your-cryptic-auth-server.com/api', tokenStorage: 'localStorage', }} autoHandleOAuthCallback={true} // Automatically handle OAuth callbacks onAuthSuccess={(user, tokens) => { console.log('User authenticated:', user); }} onError={(error) => { console.error('Auth error:', error); }} > <AppContent /> </AuthProvider> ); } // Main app content function AppContent() { return ( <AuthGuard fallback={<LoginPage />} loading={<div>Checking authentication...</div>} > <Dashboard /> </AuthGuard> ); } // Login page with OAuth options function LoginPage() { return ( <div> <h1>Welcome</h1> <div> <OAuthButton provider="google">Continue with Google</OAuthButton> <OAuthButton provider="github">Continue with GitHub</OAuthButton> </div> </div> ); } // Protected dashboard function Dashboard() { const { user, logout } = useAuth(); return ( <div> <h1>Dashboard</h1> <p>Welcome, {user?.identifier}!</p> <button onClick={logout}>Logout</button> </div> ); } ``` --- ## Advanced Usage ### Custom Token Storage ```tsx import { AuthProvider } from '@narangcia-oss/cryptic-auth-client-react'; // Custom storage implementation const customStorage = { getItem: (key: string) => { // Your custom storage logic return localStorage.getItem(key); }, setItem: (key: string, value: string) => { // Your custom storage logic localStorage.setItem(key, value); }, removeItem: (key: string) => { // Your custom storage logic localStorage.removeItem(key); }, }; function App() { return ( <AuthProvider config={{ baseURL: 'https://your-server.com/api', tokenStorage: 'custom', // Use custom storage }} > <YourApp /> </AuthProvider> ); } ``` ### Manual OAuth Callback Handling ```tsx import { useEffect } from 'react'; import { AuthProvider, isOAuthCallbackURL, cleanOAuthURL, hasOAuthError, getOAuthError } from '@narangcia-oss/cryptic-auth-client-react'; function App() { useEffect(() => { // Check if this is an OAuth callback page if (isOAuthCallbackURL()) { console.log('OAuth callback detected'); if (hasOAuthError()) { const error = getOAuthError(); console.error('OAuth error:', error); } // Clean the URL after handling setTimeout(() => { cleanOAuthURL(); }, 1000); } }, []); return ( <AuthProvider config={{ baseURL: 'https://your-server.com/api' }} autoHandleOAuthCallback={false} // Handle manually > <YourApp /> </AuthProvider> ); } ``` --- ## TypeScript Support All hooks and components are fully typed. Import types as needed: ```tsx import { AuthState, AuthContextValue, AuthProviderProps, AuthTokens, AuthUser, UserCredentials, } from '@narangcia-oss/cryptic-auth-client-react'; const MyComponent: React.FC = () => { const auth: AuthContextValue = useAuth(); const user: AuthUser | null = auth.user; return <div>{user?.identifier}</div>; }; ``` --- ## Styling The components include minimal default classes for easy styling: ```css /* OAuth Button */ .oauth-button { padding: 12px 24px; border: 1px solid #ddd; border-radius: 6px; background: white; cursor: pointer; transition: all 0.2s; } .oauth-button:hover { background: #f5f5f5; } .oauth-button-google { border-color: #4285f4; color: #4285f4; } .oauth-button-github { border-color: #333; color: #333; } /* Login Form */ .login-form { max-width: 400px; margin: 0 auto; } .form-field { margin-bottom: 1rem; } .form-field label { display: block; margin-bottom: 0.5rem; font-weight: 500; } .form-field input { width: 100%; padding: 0.75rem; border: 1px solid #ddd; border-radius: 4px; } .error-message { color: #e74c3c; font-size: 0.875rem; margin: 0.5rem 0; } .submit-button { width: 100%; padding: 0.75rem; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } .submit-button:disabled { opacity: 0.6; cursor: not-allowed; } ``` --- ## Migration from Plain TS If you're migrating from the plain TypeScript client: ```tsx // Before (plain-ts) import { AuthClient, generateOAuthState, storeOAuthState } from '@narangcia-oss/cryptic-auth-client-plain-ts'; const auth = new AuthClient({ baseURL: 'https://your-server.com/api' }); const state = generateOAuthState(); storeOAuthState(state); const url = await auth.generateOAuthAuthUrl('google', state, ['profile']); window.location.href = url; // After (react) import { useOAuth } from '@narangcia-oss/cryptic-auth-client-react'; function LoginButton() { const { login } = useOAuth(); return ( <button onClick={() => login('google', ['profile'])}> Login with Google </button> ); } ``` --- ## API Reference ### Hooks - `useAuth()` - Main authentication hook - `useUser()` - Current user information - `useOAuth()` - OAuth authentication flows - `useCredentialAuth()` - Username/password authentication - `useAuthGuard()` - Route protection ### Components - `<AuthProvider>` - Authentication context provider - `<AuthGuard>` - Conditional rendering based on auth state - `<OAuthButton>` - Pre-built OAuth login button - `<LoginForm>` - Complete login form ### Utilities - `isOAuthCallbackURL()` - Check if current URL is OAuth callback - `hasOAuthError()` - Check for OAuth errors in URL - `getOAuthError()` - Extract OAuth error details - `cleanOAuthURL()` - Remove OAuth parameters from URL - `getTokenExpiration()` - Get token expiration date - `isTokenExpiring()` - Check if token is expiring soon --- ## License MIT ---