Skip to main content
GIMA’s authentication system handles user login, logout, and session management. Currently implemented as a client-side only flow with simulated authentication.

Overview

The authentication system is a simplified implementation without backend integration. It demonstrates the UI/UX flow and routing patterns that will connect to a real authentication service.

Current Implementation

  • Client-side only: No actual credential verification
  • No session persistence: State lost on page reload
  • Simulated delay: 500ms timeout to mimic API call
  • Direct routing: Redirects to dashboard on any form submission

Architecture

User Input → Form Submission → Simulated Delay → Route to Dashboard

Login Flow

Implemented in src/app/auth/login/page.tsx.

Component State

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);

Login Function

e
React.FormEvent
required
Form submission event
void
void
Navigates to dashboard after simulated authentication delay
Implementation (from login/page.tsx:18-27):
const router = useRouter();

const handleLogin = (e: React.FormEvent) => {
  e.preventDefault();
  setIsLoading(true);

  // Simulate authentication delay
  setTimeout(() => {
    // Redirect to dashboard on successful login
    router.push("/dashboard");
  }, 500);
};
Important Notes:
  • No credential validation
  • No error handling for failed authentication
  • Loading state set but not used for UI feedback
  • 500ms artificial delay to simulate API call

Form Fields

Email/Username Field

email
string
required
User’s email or username
Implementation (from login/page.tsx:138-146):
<input
  type="email"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
  placeholder="Pedro_perez"
  className="w-full pl-12 pr-4 py-3 bg-gray-100 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition"
  required
/>
Validation: HTML5 required attribute only

Password Field

password
string
required
User’s password
showPassword
boolean
default:"false"
Toggle for password visibility
Implementation (from login/page.tsx:156-175):
<input
  type={showPassword ? "text" : "password"}
  value={password}
  onChange={(e) => setPassword(e.target.value)}
  placeholder="Pedro123"
  className="w-full pl-12 pr-12 py-3 bg-gray-100 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition"
  required
/>
<button
  type="button"
  onClick={() => setShowPassword(!showPassword)}
  className="absolute right-4 top-3.5 text-gray-400 hover:text-gray-600"
>
  {showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
</button>
Features:
  • Toggle visibility with eye icon
  • No password strength validation
  • No minimum length requirement

Form Submission

Usage Example:
<form onSubmit={handleLogin} className="space-y-6">
  {/* Email field */}
  <input
    type="email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    required
  />
  
  {/* Password field */}
  <input
    type={showPassword ? "text" : "password"}
    value={password}
    onChange={(e) => setPassword(e.target.value)}
    required
  />
  
  {/* Submit button */}
  <button
    type="submit"
    disabled={isLoading}
    className="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-full"
  >
    Accede al sistema
    <ArrowRight className="w-5 h-5" />
  </button>
</form>

Logout Flow

Implemented in src/components/layout/Sidebar.tsx.

Logout Function

void
void
Navigates user back to login page
Implementation (from Sidebar.tsx:52-55):
const router = useRouter();

const handleLogout = () => {
  // Aquí puedes agregar lógica de limpieza de tokens si es necesario
  router.push("/auth/login");
};
Important Notes:
  • No session cleanup (no tokens to clear)
  • No confirmation dialog
  • Instant redirect to login page
  • Comment indicates future token cleanup location

Logout Button

Implementation (from Sidebar.tsx:131-150):
<button
  onClick={handleLogout}
  className={cn(
    "flex items-center gap-3 w-full px-3 py-3 rounded-xl transition-all duration-200 text-gray-300 hover:text-white hover:bg-red-500/20 whitespace-nowrap",
    !isOpen && "justify-center"
  )}
  title="Cerrar sesión"
>
  <div className="min-w-6">
    <LogOut size={20} />
  </div>
  <span
    className={cn(
      "transition-all duration-300",
      isOpen ? "opacity-100" : "opacity-0 w-0 hidden"
    )}
  >
    Cerrar sesión
  </span>
</button>
Features:
  • Responsive to sidebar state (collapsed/expanded)
  • Red hover effect to indicate logout action
  • Icon from lucide-react

Session Management

Current State

No session management is currently implemented:
  • No persistence: Session lost on page reload
  • No tokens: No JWT or session cookies
  • No expiration: No automatic logout
  • No protected routes: All routes accessible without authentication

Route Protection (Not Implemented)

Currently missing middleware to protect routes:
// Future implementation needed
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const token = request.cookies.get('auth-token');
  
  if (!token && !request.nextUrl.pathname.startsWith('/auth')) {
    return NextResponse.redirect(new URL('/auth/login', request.url));
  }
  
  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Backend Integration Guide

When connecting to a real authentication backend, implement the following:

1. Login with API

const handleLogin = async (e: React.FormEvent) => {
  e.preventDefault();
  setIsLoading(true);
  
  try {
    const response = await fetch('/api/auth/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, password }),
    });
    
    if (!response.ok) {
      throw new Error('Credenciales inválidas');
    }
    
    const { token, user } = await response.json();
    
    // Store token
    localStorage.setItem('auth-token', token);
    // or use cookies for better security
    document.cookie = `auth-token=${token}; path=/; secure; httpOnly`;
    
    // Redirect to dashboard
    router.push('/dashboard');
  } catch (error) {
    console.error('Login failed:', error);
    setError('Email o contraseña incorrectos');
  } finally {
    setIsLoading(false);
  }
};

2. Logout with Session Cleanup

const handleLogout = async () => {
  try {
    // Call logout endpoint
    await fetch('/api/auth/logout', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${localStorage.getItem('auth-token')}`
      }
    });
    
    // Clear local storage
    localStorage.removeItem('auth-token');
    
    // Clear cookies
    document.cookie = 'auth-token=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT';
    
    // Redirect to login
    router.push('/auth/login');
  } catch (error) {
    console.error('Logout failed:', error);
    // Force redirect anyway
    router.push('/auth/login');
  }
};

3. Session Persistence

// app/layout.tsx or AuthProvider
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';

function useAuthCheck() {
  const router = useRouter();
  
  useEffect(() => {
    const token = localStorage.getItem('auth-token');
    
    if (!token && !window.location.pathname.startsWith('/auth')) {
      router.push('/auth/login');
    }
  }, [router]);
}

4. Token Refresh

// utils/auth.ts
export async function refreshToken() {
  try {
    const response = await fetch('/api/auth/refresh', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${localStorage.getItem('auth-token')}`
      }
    });
    
    const { token } = await response.json();
    localStorage.setItem('auth-token', token);
    
    return token;
  } catch (error) {
    // Refresh failed, redirect to login
    window.location.href = '/auth/login';
  }
}

Security Considerations

Current Vulnerabilities

  • No CSRF protection: Forms lack CSRF tokens
  • No rate limiting: Unlimited login attempts
  • Credentials in client state: Email/password stored in component state
  • No HTTPS enforcement: No secure connection requirement
  • No password requirements: Any string accepted
  1. Use HTTP-only cookies for token storage (not localStorage)
  2. Implement CSRF tokens for form submissions
  3. Add rate limiting to prevent brute force attacks
  4. Enforce HTTPS in production
  5. Implement password requirements:
    • Minimum 8 characters
    • Mix of uppercase, lowercase, numbers, special characters
  6. Add multi-factor authentication (MFA)
  7. Implement account lockout after failed attempts
  8. Log authentication events for security auditing

Password Validation Example

function validatePassword(password: string): { valid: boolean; errors: string[] } {
  const errors: string[] = [];
  
  if (password.length < 8) {
    errors.push('Mínimo 8 caracteres');
  }
  if (!/[A-Z]/.test(password)) {
    errors.push('Debe incluir mayúsculas');
  }
  if (!/[a-z]/.test(password)) {
    errors.push('Debe incluir minúsculas');
  }
  if (!/[0-9]/.test(password)) {
    errors.push('Debe incluir números');
  }
  if (!/[^A-Za-z0-9]/.test(password)) {
    errors.push('Debe incluir caracteres especiales');
  }
  
  return { valid: errors.length === 0, errors };
}

UI Features

Login Page Design

The login page features a split-screen design: Left Panel (Desktop only):
  • GIMA branding with logo
  • System description (“Gestión Inteligente de Activos y Mantenimiento”)
  • Feature highlights (Seguridad, Eficiencia, Control)
  • Gradient background (#001F3F to #002d5c)
Right Panel:
  • Welcome message
  • Email/username input with User icon
  • Password input with Lock icon and visibility toggle
  • “Remember me” checkbox
  • “Forgot password” link (non-functional)
  • Submit button with loading state

Icons Used

From lucide-react (login/page.tsx:8):
import { Eye, EyeOff, User, Lock, ArrowRight, LogOut } from "lucide-react";

Error States

Current Error Handling

No error handling is currently implemented:
  • No invalid credential messages
  • No network error handling
  • No field validation errors
  • No rate limiting messages
const [error, setError] = useState<string | null>(null);

// Show error message
{error && (
  <div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg">
    {error}
  </div>
)}

// Clear error on input change
onChange={(e) => {
  setEmail(e.target.value);
  setError(null);
}}

Build docs developers (and LLMs) love