Authentication System
Comprehensive guide to user authentication, authorization, and security in WI-CARPOOL
Authentication Overview
WI-CARPOOL implements a robust authentication system using JWT tokens with support for multiple registration and login methods. The system handles both driver and passenger user types with role-based access control.
🔐 JWT Token Authentication
Secure token-based authentication with automatic token refresh and expiry handling.
📱 Phone Verification
OTP-based phone number verification for enhanced security and user validation.
🌐 Social Login
Integration with social media platforms for quick and convenient user registration.
👥 Dual User Types
Support for both driver and passenger roles with appropriate permissions and features.
🔄 Session Management
Automatic session handling with persistent login and secure logout functionality.
🛡️ Route Protection
Protected routes ensure only authenticated users can access restricted areas.
Authentication Flow
The authentication process follows a secure, multi-step approach:
1. User Registration
Users choose their role (driver/passenger) and provide basic information including phone number for verification.
2. Phone Verification
OTP sent to user's phone number for verification. Account activation requires successful OTP validation.
3. Profile Completion
Users complete their profiles with additional information, preferences, and required documents (for drivers).
4. JWT Token Generation
Successful authentication generates JWT tokens for secure API access and session management.
5. Role-Based Access
Users are redirected to appropriate dashboards based on their role with relevant features and permissions.
6. Session Persistence
Secure token storage enables persistent sessions across browser sessions and automatic login.
Authentication Components
The authentication system is built using modular React components:
Authentication Component Structure
src/components/auth/
├── SignInCard.tsx # Main sign-in form component
├── SignUpCard.tsx # User registration form
├── PhoneLoginForm.tsx # Phone number login form
├── SocialLoginButtons.tsx # Social media login options
├── UserRegistrationForm.tsx # Complete registration form
└── UserTypeToggle.tsx # Driver/Passenger role selector
Sign-In Component
The SignInCard
component handles user login with email/phone and password:
SignInCard Features
// Key features of the SignInCard component
- Email or phone number input
- Password field with visibility toggle
- Remember me functionality
- Forgot password link
- Social login integration
- Role-based redirects after login
- Form validation with error handling
- Loading states during authentication
Registration Component
The SignUpCard
component manages new user registration:
SignUpCard Features
// Registration form capabilities
- User type selection (driver/passenger)
- Basic information collection (name, email, phone)
- Password creation with strength validation
- Country and language selection
- Currency preference setting
- Terms and conditions acceptance
- Phone verification workflow
- Automatic login after registration
Authentication Context
The authentication state is managed through React Context API:
AuthContext Structure
// Authentication context provides global auth state
interface AuthContextType {
user: User | null; // Current authenticated user
isAuthenticated: boolean; // Authentication status
isLoading: boolean; // Loading state
login: (credentials) => Promise; // Login function
logout: () => void; // Logout function
register: (userData) => Promise; // Registration function
updateUser: (userData) => void; // Update user data
}
Using Authentication Context
// How to use auth context in components
import { useAuth } from '@/contexts/auth/useAuth';
function ProtectedComponent() {
const { user, isAuthenticated, logout } = useAuth();
if (!isAuthenticated) {
return ;
}
return (
<div>
<p>Welcome, {user?.name}!</p>
<button onClick={logout}>Logout</button>
</div>
);
}
Protected Routes
The application uses protected routes to ensure only authenticated users can access restricted areas:
ProtectedRoute Component
// Protected route implementation
import { useAuth } from '@/contexts/auth/useAuth';
import { Navigate } from 'react-router-dom';
interface ProtectedRouteProps {
children: React.ReactNode;
requireAuth?: boolean;
userType?: 'driver' | 'passenger';
}
export function ProtectedRoute({
children,
requireAuth = true,
userType
}: ProtectedRouteProps) {
const { isAuthenticated, user, isLoading } = useAuth();
if (isLoading) {
return <LoadingSpinner />;
}
if (requireAuth && !isAuthenticated) {
return <Navigate to="/signin" replace />;
}
if (userType && user?.user_type !== userType) {
return <Navigate to="/unauthorized" replace />;
}
return <>{children}</>;
}
Route Protection Examples
Different Protection Levels
// Public route - no authentication required
<Route path="/" element={<HomePage />} />
// Protected route - authentication required
<Route path="/dashboard" element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
} />
// Role-specific route - driver only
<Route path="/driver/*" element={
<ProtectedRoute userType="driver">
<DriverRoutes />
</ProtectedRoute>
} />
// Role-specific route - passenger only
<Route path="/passenger/*" element={
<ProtectedRoute userType="passenger">
<PassengerRoutes />
</ProtectedRoute>
} />
API Authentication
All API requests are automatically authenticated using axios interceptors:
Axios Request Interceptor
// Automatic token attachment in axios instance
axiosInstance.interceptors.request.use(
(config) => {
const token = getToken(); // Get token from localStorage
if (token) {
// Add token as URL parameter
config.params = { ...config.params, token };
// Add Authorization header
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
Response Interceptor for Auth Errors
// Handle authentication errors automatically
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Token expired or invalid
localStorage.removeItem('user');
window.location.href = '/signin';
}
return Promise.reject(error);
}
);
User Registration Process
The registration process supports both drivers and passengers with role-specific requirements:
Basic Registration
- Name - Full name validation
- Email - Email format validation
- Phone - Phone number with country code
- Password - Strong password requirements
- User Type - Driver or passenger selection
Additional Information
- Country - Country selection for localization
- Language - Preferred language setting
- Currency - Local currency preference
- Company - Optional company affiliation
Driver-Specific Requirements
- Driver's License - License verification
- Vehicle Information - Car details and documents
- Insurance Documents - Valid insurance proof
- Background Check - Safety verification process
Verification Steps
- Phone Verification - OTP validation
- Email Confirmation - Email verification link
- Document Review - Manual document verification
- Account Activation - Final account approval
Social Login Integration
WI-CARPOOL supports social login for quick and convenient user onboarding:
Social Login Implementation
// Social login component structure
function SocialLoginButtons() {
const handleSocialLogin = async (provider: string) => {
try {
// Redirect to social provider OAuth
const response = await authService.socialSignup({
provider,
device_id: generateDeviceId(),
device_type: 'web'
});
if (response.data.status === 'success') {
// Handle successful social login
setUser(response.data.user);
navigate('/dashboard');
}
} catch (error) {
// Handle social login errors
console.error('Social login failed:', error);
}
};
return (
<div className="social-login-buttons">
<button onClick={() => handleSocialLogin('google')}>
Continue with Google
</button>
<button onClick={() => handleSocialLogin('facebook')}>
Continue with Facebook
</button>
<button onClick={() => handleSocialLogin('apple')}>
Continue with Apple
</button>
</div>
);
}
Supported Social Providers
- Google - Google OAuth 2.0 integration
- Facebook - Facebook Login API
- Apple - Sign in with Apple
Password Security
The application implements strong password policies and security measures:
🔒 Password Requirements
Minimum 8 characters with complexity requirements for secure user accounts.
👁️ Password Visibility
Toggle password visibility for better user experience during input.
🔄 Password Reset
Secure password reset flow with email verification and temporary tokens.
🛡️ Password Validation
Real-time password strength validation with helpful feedback.
Password Reset Flow
// Password reset implementation
const handleForgotPassword = async (email: string) => {
try {
const response = await authService.forgotPassword({
email,
device_id: generateDeviceId()
});
if (response.data.status === 'success') {
toast({
title: 'Reset link sent',
description: 'Check your email for password reset instructions.'
});
}
} catch (error) {
toast({
title: 'Error',
description: 'Failed to send reset link. Please try again.',
variant: 'destructive'
});
}
};
Session Management
Robust session management ensures secure and persistent user authentication:
Token Storage and Management
// Token management utilities
export const tokenManager = {
// Store token securely in localStorage
setToken: (user: User) => {
localStorage.setItem('user', JSON.stringify(user));
},
// Retrieve token from storage
getToken: (): string | null => {
try {
const userData = localStorage.getItem('user');
if (userData) {
const user = JSON.parse(userData);
return user.token || user.access_token || null;
}
return null;
} catch {
return null;
}
},
// Remove token and clear session
clearToken: () => {
localStorage.removeItem('user');
},
// Check if token exists and is valid
isTokenValid: (): boolean => {
const token = tokenManager.getToken();
return !!token; // Additional JWT validation can be added
}
};
Automatic Session Restoration
Session Restoration on App Load
// AuthProvider automatically restores sessions
useEffect(() => {
const initializeAuth = () => {
try {
const userData = localStorage.getItem('user');
if (userData) {
const user = JSON.parse(userData);
if (user.token || user.access_token) {
setUser(user);
setIsAuthenticated(true);
}
}
} catch (error) {
console.error('Failed to restore session:', error);
localStorage.removeItem('user');
} finally {
setIsLoading(false);
}
};
initializeAuth();
}, []);
Security Considerations
Token Security
- JWT Tokens - Stateless authentication tokens
- Secure Storage - Local storage with proper cleanup
- Token Expiry - Automatic session timeout handling
- Device Tracking - Device ID for session management
Data Protection
- HTTPS Only - Encrypted data transmission
- Input Validation - Client and server-side validation
- XSS Protection - Sanitized user inputs
- CSRF Protection - Cross-site request forgery prevention
Privacy Features
- Data Minimization - Collect only necessary information
- Consent Management - Terms and privacy acceptance
- Right to Deletion - Account deletion capabilities
- Data Portability - User data export options
Monitoring & Alerts
- Failed Login Attempts - Brute force protection
- Suspicious Activity - Unusual login pattern detection
- Security Logs - Authentication event logging
- Notification System - Security alerts to users
Error Handling
Comprehensive error handling ensures smooth user experience during authentication:
Authentication Error Types
// Common authentication errors and handling
const authErrorMessages = {
'invalid_credentials': 'Invalid email or password',
'user_not_found': 'No account found with this email',
'account_suspended': 'Your account has been suspended',
'verification_required': 'Please verify your phone number',
'invalid_otp': 'Invalid OTP code',
'otp_expired': 'OTP code has expired',
'social_login_failed': 'Social login failed. Please try again',
'network_error': 'Connection error. Please check your internet',
'server_error': 'Server error. Please try again later'
};
// Error handling in login function
const handleLoginError = (error: any) => {
const errorCode = error.response?.data?.error_code;
const message = authErrorMessages[errorCode] || 'Login failed';
toast({
title: 'Authentication Error',
description: message,
variant: 'destructive'
});
};
Multi-language Authentication
Authentication components support multiple languages through the i18n system:
Internationalized Authentication
// Using translations in auth components
import { useTranslation } from '@/hooks/useTranslation';
function SignInCard() {
const { t } = useTranslation();
return (
<form>
<label>{t('auth.email_label')}</label>
<input placeholder={t('auth.email_placeholder')} />
<label>{t('auth.password_label')}</label>
<input placeholder={t('auth.password_placeholder')} />
<button>{t('auth.sign_in_button')}</button>
<a href="/forgot-password">
{t('auth.forgot_password_link')}
</a>
</form>
);
}
Testing Authentication
To test the authentication system:
1. Registration Testing
Test user registration with different roles, validation scenarios, and error cases.
2. Login Testing
Verify email/phone login, password validation, and session persistence.
3. OTP Verification
Test phone verification flow, OTP validation, and expiry handling.
4. Social Login
Verify social login integration with different providers and edge cases.
5. Route Protection
Test protected routes, role-based access, and unauthorized access handling.
6. Session Management
Verify session persistence, token expiry, and automatic logout functionality.