Authentication & AuthorizationΒΆ
Section: 5-security-architecture
Document: Authentication & Authorization
Status: Comprehensive Implementation Documentation
Audience: Security teams, developers, compliance officers
π― OverviewΒΆ
MachineAvatars implements a multi-layered authentication and authorization system combining email/password authentication, OTP verification, JWT tokens, role-based access control (RBAC), and enterprise SSO capabilities.
Authentication Methods:
- Email/Password (with OTP verification)
- reCAPTCHA v2 (bot protection)
- Single Sign-On (SSO) - Enterprise only
Authorization:
- Role-Based Access Control (RBAC)
- 5 roles with granular permissions
- Chatbot-level access control
- Department partitioning (Enterprise)
π Authentication ArchitectureΒΆ
Multi-Service Authentication FlowΒΆ
graph TB
subgraph "Client"
A[Frontend]
end
subgraph "Gateway"
B[Gateway Service<br/>Port 8000/9000]
end
subgraph "Authentication Services"
C[Auth Service<br/>Port 8001<br/>LOGIN ONLY]
D[User Service<br/>Port 8002<br/>SIGNUP, OTP, RESET]
end
subgraph "External Services"
E[Azure Communication<br/>Email Service]
F[Google<br/>reCAPTCHA v2]
end
subgraph "Database"
G[(MongoDB<br/>users collection)]
end
A -->|1. POST /v2/signup| B
B --> D
D -->|2. Send OTP| E
D -->|3. Create user| G
A -->|4. POST /v2/verify-otp| B
B --> D
D -->|5. Activate user| G
A -->|6. POST /v2/login| B
B -->|7. Verify reCAPTCHA| F
F -->|8. Token valid| B
B --> C
C -->|9. Validate credentials| G
C -->|10. Issue JWT| B
B -->|11. Return token| A
style C fill:#FFE082
style D fill:#E3F2FD
Service ResponsibilitiesΒΆ
| Function | Auth Service (8001) | User Service (8002) | Gateway Service |
|---|---|---|---|
| Login | β Validate & issue JWT | β | β reCAPTCHA check |
| Signup | β | β Create user + OTP | β Forward request |
| OTP Generation | β | β 6-digit code | β |
| Email Sending | β | β Azure Communication | β |
| OTP Verification | β | β Verify + activate | β |
| Password Reset | β | β OTP-based reset | β |
| JWT Creation | β Primary function | β Helper function | β |
| JWT Validation | β | β | β Token verification |
π§ Email/Password AuthenticationΒΆ
1. Signup FlowΒΆ
Endpoint: POST /v2/signup
Service: User Service (Port 8002)
Response Time: 2-5 seconds (includes email sending)
Complete Signup ProcessΒΆ
sequenceDiagram
participant C as Client
participant G as Gateway
participant U as User Service
participant DB as MongoDB
participant AZ as Azure Email
C->>G: POST /v2/signup<br/>(email, password, name)
G->>U: Forward request
Note over U: Step 1: Check existing user
U->>DB: findOne({email})
DB-->>U: User or null
alt User exists & verified
U-->>C: 400 "Email already registered"
end
alt User exists & unverified
Note over U: Resend OTP flow
U->>U: generate_otp() β "123456"
U->>AZ: Send OTP email
AZ-->>U: Email sent
U->>DB: Update OTP & expiry
U-->>C: 200 {token}
end
alt New user
Note over U: Create new user
U->>U: generate_otp() β "654321"
U->>AZ: Send OTP email
AZ-->>U: Email sent
U->>DB: insertOne(user with OTP)
U-->>C: 200 {token}
end
Request FormatΒΆ
const formData = new FormData();
formData.append("email", "user@example.com");
formData.append("password", "mySecurePassword123");
formData.append("name", "John Doe");
const response = await fetch(`${API_URL}/v2/signup`, {
method: "POST",
body: formData,
});
Success ResponseΒΆ
JWT Payload:
New User Document CreatedΒΆ
{
"_id": ObjectId("65a1b2c3d4e5f6789abc"),
"email": "user@example.com",
"password": "mypassword123", // β οΈ PLAIN TEXT - SECURITY ISSUE!
"name": "John Doe",
"otp": "654321",
"otp_expiration": 1735214460, // Unix timestamp (60 seconds)
"verified": false, // Cannot login yet
"account_status": "paused", // Activated after OTP verification
"payment_status": "pending",
"user_created_at(DATE)": "2025-01-15",
"subscription_id": "sub_009", // Free plan by default
"subscription_date": "2025-01-15"
// Note: user_id NOT set yet (assigned during OTP verification)
}
2. OTP Verification SystemΒΆ
Endpoint: POST /v2/verify-otp
Service: User Service (Port 8002)
Expiry: 60 seconds
OTP GenerationΒΆ
Characteristics:
- Length: 6 digits
- Character Set: 0-9
- Total Combinations: 1,000,000
- Expiry: 60 seconds
- Format: "123456", "987654", etc.
Security Note: With 60-second expiry and 1M combinations, brute force is difficult but not impossible.
Recommendations:
- β Rate limiting (3 attempts per minute) - NOT IMPLEMENTED
- β Account lockout after 5 failed attempts - NOT IMPLEMENTED
- β IP-based blocking for abuse - NOT IMPLEMENTED
Email Delivery (Azure Communication Services)ΒΆ
Configuration:
EMAIL_ENDPOINT = "https://mailing-sevice.india.communication.azure.com/"
EMAIL_ACCESS_KEY = "CgdEWi6fBCJv..." # β οΈ HARDCODED - SECURITY ISSUE!
SENDER_EMAIL = "DoNotReply@machineagents.ai"
Email Content:
- Subject: "Your OTP Code"
- Body: "Your OTP is 123456. It is valid for 60 seconds."
- Delivery Time: 1-5 seconds
- Provider: Azure Communication Email (India region)
Improvement Needed:
Welcome to MachineAvatars!
Your verification code is: 123456
This code will expire in 60 seconds.
If you did not request this code, please ignore this email.
---
MachineAvatars Team
https://machine avatars.com
OTP Verification FlowΒΆ
sequenceDiagram
participant C as Client
participant U as User Service
participant DB as MongoDB
C->>U: POST /v2/verify-otp<br/>(email, otp)
U->>DB: findOne({email})
DB-->>U: User document
alt User not found
U-->>C: 404 "User not found"
end
alt OTP expired
Note over U: time.time() > otp_expiration
U-->>C: 400 "OTP expired"
end
alt OTP invalid
Note over U: user["otp"] != otp
U-->>C: 400 "Invalid OTP"
end
alt OTP valid
Note over U: Generate user_id
U->>U: user_id = "User-123456"
U->>DB: updateOne(verified=true, user_id, active)
Note over U: Assign free plan features
U->>U: assign_free_plan_features(user_id)
U->>DB: Insert features_per_user
U-->>C: 200 {message, user_id}
end
Request & ResponseΒΆ
Request:
Success Response:
Account ActivationΒΆ
Database Update:
db.users_multichatbot_v2.updateOne(
{ email: "user@example.com" },
{
$set: {
verified: true, // Now can login
user_id: "User-123456", // Unique identifier
account_status: "active", // Was "paused"
},
}
);
User ID Generation:
Collision Risk: Low but possible (1 in 1 million)
Better Approach:
import time
user_id = f"User-{int(time.time())}_{random.randint(100, 999)}"
# Example: "User-1735214400_456"
3. Login FlowΒΆ
Endpoint: POST /v2/login
Service: Auth Service (Port 8001)
Response Time: 50-100ms
Complete Login ProcessΒΆ
sequenceDiagram
participant C as Client (Frontend)
participant G as Gateway
participant RC as reCAPTCHA v2
participant A as Auth Service
participant DB as MongoDB
C->>C: User enters email, password
C->>RC: Complete reCAPTCHA
RC-->>C: reCAPTCHA token
C->>G: POST /v2/login<br/>(email, password, recaptcha_token)
G->>RC: Verify reCAPTCHA token
RC-->>G: Token valid
alt reCAPTCHA invalid
G-->>C: 400 "reCAPTCHA validation failed"
end
G->>A: Forward login request
A->>DB: findOne({email})
DB-->>A: User document or null
alt User not found
A-->>C: 404 "User does not exist"
end
alt Password mismatch
Note over A: user["password"] != password<br/>β οΈ PLAIN TEXT COMPARISON!
A-->>C: 401 "Invalid credentials"
end
alt Not verified
Note over A: verified != true
A-->>C: 403 "Account not verified"
end
alt Login successful
Note over A: Generate JWT
A->>A: create_jwt_token({email, user_id})
A-->>C: 200 {token, user_id}
C->>C: Store in sessionStorage
C->>C: Redirect to /chatbots
end
reCAPTCHA v2 IntegrationΒΆ
Frontend Implementation:
// Configuration
const RECAPTCHA_SITE_KEY = process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY;
// Rendering
window.grecaptcha.render(container, {
sitekey: RECAPTCHA_SITE_KEY,
callback: (token: string) => setRecaptchaToken(token),
"expired-callback": () => setRecaptchaToken(""),
theme: "dark",
});
Features:
- β Dark theme
- β Auto-expiry after 2 minutes
- β Retry on render failure
- β Proper cleanup on unmount
- β Reset on login error
Gateway Verification (Inferred):
# Gateway should verify reCAPTCHA token before forwarding
import requests
def verify_recaptcha(token, secret_key):
response = requests.post(
'https://www.google.com/recaptcha/api/siteverify',
data={
'secret': secret_key,
'response': token
}
)
return response.json().get('success', False)
Password ValidationΒΆ
Current Implementation (CRITICAL SECURITY ISSUE):
if user["password"] != password: # β οΈ PLAIN TEXT COMPARISON!
raise HTTPException(status_code=401, detail="Invalid credentials")
Problems:
- Passwords stored in plain text in database
- Database breach = all passwords exposed
- Violates OWASP, GDPR, PCI-DSS, DPDPA standards
- No password hashing whatsoever
Required Implementation (bcrypt):
import bcrypt
# On signup (User Service)
password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12))
users_collection.insert_one({
"email": email,
"password_hash": password_hash.decode('utf-8'), # Store hash, not plain text
...
})
# On login (Auth Service)
if not bcrypt.checkpw(password.encode('utf-8'), user["password_hash"].encode('utf-8')):
raise HTTPException(status_code=401, detail="Invalid credentials")
Migration Plan:
- Add
password_hashfield to schema - Hash existing plain text passwords (one-time script)
- Update signup to store hashed passwords
- Update login to use bcrypt.checkpw()
- Remove
passwordfield after migration
4. JWT Token SystemΒΆ
Algorithm: HS256 (HMAC with SHA-256)
Expiry: 30 minutes
Secret: Environment variable JWT_SECRET
Token GenerationΒΆ
def create_jwt_token(data: dict, expires_delta: timedelta = timedelta(minutes=30)):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
return jwt.encode(to_encode, JWT_SECRET, algorithm="HS256")
Token StructureΒΆ
Full JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VyX2lkIjoiVXNlcl8xMjM0NSIsImV4cCI6MTczNTIxNDQwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
HEADER . PAYLOAD . SIGNATURE
Header:
Payload:
Signature:
Token ValidationΒΆ
Where Validated:
- Gateway Service (should validate - NOT CONFIRMED)
- Individual services (should validate before processing)
- Frontend (checks expiry)
Validation Code (Example):
import jwt
from fastapi import HTTPException, Header
def verify_token(authorization: str = Header(None)):
if not authorization:
raise HTTPException(status_code=401, detail="No authorization header")
try:
# Remove "Bearer " prefix
token = authorization.replace("Bearer ", "")
# Decode and verify
payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
return payload # {"email": "...", "user_id": "..."}
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
Frontend StorageΒΆ
Session Storage (Current):
// On successful login
sessionStorage.setItem("isLoggedIn", "true");
sessionStorage.setItem("authToken", data.token);
sessionStorage.setItem("user_id", data.user_id);
sessionStorage.setItem("session_id", data.session_id || generateSessionId());
sessionStorage.setItem("userEmail", email);
Usage in Requests:
fetch("https://api.example.com/chatbots", {
headers: {
Authorization: `Bearer ${sessionStorage.getItem("authToken")}`,
},
});
Security Considerations:
- β sessionStorage (cleared on tab close)
- β οΈ Vulnerable to XSS attacks
- β οΈ No HttpOnly cookies (more secure alternative)
Recommended: HttpOnly Cookies
// Backend sets cookie
response.set_cookie(
(key = "auth_token"),
(value = token),
(httponly = True), // Not accessible via JavaScript
(secure = True), // HTTPS only
(samesite = "strict"), // CSRF protection
(max_age = 1800) // 30 minutes
);
5. Password Reset FlowΒΆ
3-Step Process:
- Request reset (send OTP)
- Verify OTP
- Set new password
Step 1: Forgot PasswordΒΆ
Endpoint: POST /v2/forgot-password
Service: User Service (Port 8002)
Request:
Process:
- Check if user exists
- Generate 6-digit OTP
- Send OTP via email
- Update
otpandotp_expirationin database - Return JWT token
Response:
Step 2 & 3: Reset PasswordΒΆ
Endpoint: POST /v2/reset-password
Service: User Service (Port 8002)
Request:
formData.append("email", "user@example.com");
formData.append("otp", "123456");
formData.append("new_password", "newSecurePassword456");
Process:
- Validate OTP (same as verify-otp)
- Check OTP expiration
- Update password in database (β οΈ still plain text!)
- Return JWT token
Response:
Complete Flow:
sequenceDiagram
participant C as Client
participant U as User Service
participant DB as MongoDB
participant E as Azure Email
Note over C: Step 1: Request Reset
C->>U: POST /v2/forgot-password<br/>(email)
U->>DB: findOne({email})
alt User not found
U-->>C: 404 "User not found"
end
U->>U: generate_otp()
U->>E: Send OTP email
U->>DB: Update OTP & expiry
U-->>C: 200 {token}
Note over C: Step 2: User receives email
Note over C: Step 3: Submit new password
C->>U: POST /v2/reset-password<br/>(email, otp, new_password)
U->>DB: findOne({email})
alt OTP invalid/expired
U-->>C: 400 "Invalid/Expired OTP"
end
U->>DB: Update password
U-->>C: 200 {token}
C->>C: Redirect to login
π‘οΈ Authorization & Access ControlΒΆ
Role-Based Access Control (RBAC)ΒΆ
5 Roles Defined:
- Owner - Full control over account
- Admin - Manage chatbots and users (no billing access)
- Editor - Create and edit chatbots
- Viewer - Read-only access to chatbots and analytics
- Analyst - Access to analytics and reports only
Permissions MatrixΒΆ
| Feature | Owner | Admin | Editor | Viewer | Analyst |
|---|---|---|---|---|---|
| Chatbot Management | |||||
| Create Chatbot | β | β | β | β | β |
| Edit Chatbot | β | β | β | β | β |
| Delete Chatbot | β | β | β | β | β |
| View Chatbot | β | β | β | β | β |
| Duplicate Chatbot | β | β | β | β | β |
| User Management | |||||
| Add Users | β | β | β | β | β |
| Edit Users | β | β | β | β | β |
| Remove Users | β | β | β | β | β |
| Assign Roles | β | β | β | β | β |
| View Users | β | β | β | β | β |
| Billing & Subscription | |||||
| View Billing | β | β | β | β | β |
| Manage Payment | β | β | β | β | β |
| Upgrade/Downgrade Plan | β | β | β | β | β |
| Analytics & Reports | |||||
| View Analytics | β | β | β | β | β |
| Export Data | β | β | β | β | β |
| Custom Reports | β | β | β | β | β |
| System Prompts | |||||
| Edit System Prompts | β | β | β | β | β |
| View Prompts | β | β | β | β | β |
| Data Management | |||||
| Upload Files | β | β | β | β | β |
| Add URLs | β | β | β | β | β |
| Manage Q&A | β | β | β | β | β |
| View Knowledge Base | β | β | β | β | β |
Chatbot-Level PermissionsΒΆ
Access Control Lists (ACLs):
Users can be granted specific permissions per chatbot:
{
"chatbot_id": "chatbot_123",
"permissions": [
{
"user_id": "User-456",
"role": "Editor",
"granted_by": "User-789", // Owner
"granted_at": "2025-01-15T10:00:00Z"
},
{
"user_id": "User-321",
"role": "Viewer",
"granted_by": "User-789",
"granted_at": "2025-01-16T14:30:00Z"
}
]
}
Department Partitioning (Enterprise)ΒΆ
Structure:
Organization: ACME Corp
βββ Department: Sales
β βββ User: sales-admin@acme.com (Admin)
β βββ User: sales-rep@acme.com (Editor)
β βββ Chatbot: Product Demo
β βββ Chatbot: Lead Qualifier
βββ Department: Support
β βββ User: support-manager@acme.com (Admin)
β βββ User: support-agent@acme.com (Editor)
β βββ Chatbot: Help Center
β βββ Chatbot: Troubleshooting
βββ Department: HR
βββ User: hr-manager@acme.com (Admin)
βββ Chatbot: Employee Onboarding
Benefits:
- Data isolation between departments
- Independent billing per department
- Department-specific analytics
- Role inheritance within department
π’ Enterprise Single Sign-On (SSO)ΒΆ
Availability: Premium Plan only
Status: Implemented
Supported ProtocolsΒΆ
1. SAML 2.0ΒΆ
Identity Providers:
- Okta
- OneLogin
- Azure Active Directory
- Google Workspace
- Custom SAML providers
Configuration:
<!-- Service Provider Metadata -->
<EntityDescriptor entityID="https://machineavatars.com/saml">
<SPSSODescriptor>
<AssertionConsumerService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://machineavatars.com/saml/acs"
index="0"/>
</SPSSODescriptor>
</EntityDescriptor>
SAML Flow:
sequenceDiagram
participant U as User
participant MA as MachineAvatars
participant IDP as Identity Provider (Okta)
U->>MA: Access /login
MA->>MA: Detect SSO enabled
MA->>IDP: SAML AuthnRequest
IDP->>U: Show login page
U->>IDP: Enter credentials
IDP->>IDP: Authenticate
IDP->>MA: SAML Response (Assertion)
MA->>MA: Validate assertion
MA->>MA: Create user session
MA->>U: Redirect to /chatbots
Attributes Mapped:
emailβ User emailfirstNameβ User first namelastNameβ User last nameroleβ RBAC role (if provided)departmentβ Department assignment
2. OAuth 2.0 / OpenID ConnectΒΆ
Identity Providers:
- Google Workspace
- Microsoft 365 (Azure AD)
- GitHub Enterprise
OAuth Flow:
sequenceDiagram
participant U as User
participant MA as MachineAvatars
participant OAuth as OAuth Provider
U->>MA: Click "Sign in with Google"
MA->>OAuth: Authorization request
OAuth->>U: Show consent screen
U->>OAuth: Grant permission
OAuth->>MA: Authorization code
MA->>OAuth: Exchange code for token
OAuth->>MA: Access token + ID token
MA->>MA: Validate ID token
MA->>MA: Create/update user
MA->>U: Redirect to /chatbots
Configuration Example (Google):
const oauth2Config = {
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
redirect_uri: "https://machineavatars.com/oauth/callback",
scope: "openid email profile",
response_type: "code",
};
3. LDAP IntegrationΒΆ
Use Case: On-premise Active Directory
Connection:
import ldap
ldap_server = "ldap://ad.company.com:389"
bind_dn = "CN=ServiceAccount,OU=Services,DC=company,DC=com"
bind_password = "SecurePassword123"
connection = ldap.initialize(ldap_server)
connection.simple_bind_s(bind_dn, bind_password)
Authentication:
def authenticate_ldap(username, password):
user_dn = f"CN={username},OU=Users,DC=company,DC=com"
try:
connection.simple_bind_s(user_dn, password)
return True
except ldap.INVALID_CREDENTIALS:
return False
SSO User ProvisioningΒΆ
Automatic Provisioning:
- User logs in via SSO (first time)
- MachineAvatars receives user attributes
- Check if user exists (by email)
- If new: Create user account automatically
- If existing: Update user attributes
- Assign default role (from SSO or Free plan)
- Redirect to dashboard
Just-In-Time (JIT) Provisioning:
- Users created on first SSO login
- No pre-provisioning required
- Attributes synced from IDP
Deprovisioning:
- User disabled in IDP β session invalidated in MachineAvatars
- User deleted in IDP β admin notified (manual action required)
π Security Best Practices & RecommendationsΒΆ
Critical Issues to Fix (Priority Order)ΒΆ
1. CRITICAL: Plain Text PasswordsΒΆ
Status: β οΈ NOT FIXED
Current:
Required:
import bcrypt
# Signup
password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12))
# Login
if not bcrypt.checkpw(password.encode('utf-8'), user["password_hash"].encode('utf-8')):
raise HTTPException(status_code=401)
Migration Steps:
- Add
password_hashfield to users collection - Run migration script to hash existing passwords
- Update signup endpoint to use bcrypt
- Update login endpoint to use bcrypt.checkpw()
- Remove
passwordfield after 100% migration
Timeline: IMMEDIATE (Q1 2025)
2. CRITICAL: Hardcoded SecretsΒΆ
Status: β οΈ NOT FIXED
Problems:
# user-service/src/utils/email_utils.py
EMAIL_ACCESS_KEY = "CgdEWi6fBCJv4c0EHOkq6ZUSML0VQSG49qXgEfrtlLmXY76HV7DeJQQJ99BBACULyCplbknJAAAAAZCSbc3T"
# auth-service/src/main.py
JWT_SECRET = os.getenv("JWT_SECRET", "your_jwt_secret") # Weak default
Required:
# Environment variables only
EMAIL_ACCESS_KEY = os.getenv("AZURE_EMAIL_KEY")
if not EMAIL_ACCESS_KEY:
raise ValueError("AZURE_EMAIL_KEY must be set")
JWT_SECRET = os.getenv("JWT_SECRET")
if not JWT_SECRET:
raise ValueError("JWT_SECRET must be set")
Best Practice: Use Azure Key Vault
Timeline: IMMEDIATE (Q1 2025)
3. HIGH: CORS Allows All OriginsΒΆ
Status: β οΈ NOT FIXED
Current:
Required:
allow_origins=[
"https://machineavatars.com",
"https://app.machineavatars.com",
"http://localhost:3000" # Dev only
]
Timeline: Q1 2025
4. HIGH: No Rate LimitingΒΆ
Status: β οΈ NOT IMPLEMENTED
Required:
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/v2/login")
@limiter.limit("5/minute") # 5 attempts per minute
async def login(...):
...
Timeline: Q1 2025
5. MEDIUM: Session Storage (XSS Vulnerable)ΒΆ
Current: sessionStorage (JavaScript accessible)
Recommended: HttpOnly cookies
Timeline: Q2 2025
Additional RecommendationsΒΆ
1. Multi-Factor Authentication (MFA):
- β Email OTP (implemented)
- β³ SMS OTP (planned)
- β³ Authenticator app (Google Authenticator, Authy)
- β³ Biometric (mobile apps)
2. Session Management:
- β³ Session timeout (30-minute inactivity)
- β³ Concurrent session limits
- β³ Force re-authentication for sensitive actions
- β³ Session invalidation on password change
3. Audit Logging:
- β Basic logging (login attempts)
- β³ Failed login attempts tracking
- β³ Permission changes logging
- β³ Suspicious activity detection
π Frontend Authentication PatternsΒΆ
Protected RoutesΒΆ
Implementation:
// components/ProtectedLayout.tsx
export function ProtectedLayout({ children }) {
const router = useRouter();
useEffect(() => {
const isLoggedIn = sessionStorage.getItem("isLoggedIn");
const authToken = sessionStorage.getItem("authToken");
if (!isLoggedIn || !authToken) {
router.push("/login");
}
}, [router]);
return <>{children}</>;
}
Usage:
// app/chatbots/page.tsx
export default function ChatbotsPage() {
return (
<ProtectedLayout>
<ChatbotsList />
</ProtectedLayout>
);
}
Admin Redirect (Superadmin Feature)ΒΆ
Purpose: Allow superadmin to log in as any user for support
URL Format:
Implementation:
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const isAdminRedirect = urlParams.get("adminRedirect");
if (isAdminRedirect === "true") {
const token = urlParams.get("token");
const userId = urlParams.get("user_id");
const sessionId = urlParams.get("session_id");
const email = urlParams.get("email");
if (token && userId) {
sessionStorage.setItem("isLoggedIn", "true");
sessionStorage.setItem("authToken", token);
sessionStorage.setItem("user_id", userId);
sessionStorage.setItem("session_id", sessionId || generateSessionId());
sessionStorage.setItem("userEmail", email || "");
sessionStorage.setItem("connectedFromSuperAdmin", "true"); // Flag for UI
window.history.replaceState({}, document.title, window.location.pathname);
router.push("/chatbots");
}
}
}, [router]);
Security Considerations:
- β Token must be valid JWT
- β URL parameters cleaned from history
- β οΈ No IP validation
- β οΈ No superadmin session tracking
Auto-Logout on Token ExpiryΒΆ
Current: Manual check on page load
Recommended:
useEffect(() => {
const checkTokenExpiry = () => {
const token = sessionStorage.getItem("authToken");
if (!token) return;
try {
const payload = JSON.parse(atob(token.split(".")[1]));
const exp = payload.exp * 1000; // Convert to milliseconds
if (Date.now() >= exp) {
// Token expired
sessionStorage.clear();
router.push("/login");
}
} catch (error) {
sessionStorage.clear();
router.push("/login");
}
};
// Check every minute
const interval = setInterval(checkTokenExpiry, 60000);
checkTokenExpiry(); // Check immediately
return () => clearInterval(interval);
}, [router]);
π Related DocumentationΒΆ
Backend Services:
- Auth Service - Login implementation
- User Service - Signup, OTP, password reset
- Gateway Service - reCAPTCHA verification
Frontend:
- Authentication Pages - Login, signup, password reset pages
- Hooks - useAuth, useSessionData
Features:
- Platform Capabilities - Auth features by plan
- Enterprise Features - SSO, RBAC details
- Admin & Management - User management
Security:
- Secret Management - API key management
- Compliance Controls - GDPR, DPDPA requirements
"Secure authentication is the foundation of trust." πβ