Skip to main content

Overview

The Authentication Actions module provides server-side functions for handling user authentication with a Laravel Sanctum backend. It manages secure token storage using HTTP-only cookies.
The current implementation includes hardcoded credentials for development/testing purposes. This should be replaced with proper authentication flows in production.

loginSilent

Performs an automatic login using predefined credentials. Retrieves a Sanctum authentication token and stores it in an HTTP-only cookie.
export async function loginSilent(): Promise<string | null>

Response

return
string | null
Returns the authentication token on success, or null on failure

Features

  • HTTP-Only Cookies: Stores token securely, inaccessible to JavaScript
  • TLS Bypass: Disables certificate validation in development for self-signed certificates
  • Automatic Configuration: Reads backend URL from environment variables
  • Session Management: Configures cookie with 7-day expiration
PropertyValueDescription
Nameauth_tokenCookie name
HttpOnlytruePrevents XSS access
Securetrue (production)HTTPS-only in production
SameSitelaxCSRF protection
Path/Available site-wide
MaxAge604800 seconds7 days

Example

const token = await loginSilent();

if (token) {
  console.log('[Auth] Login successful');
  // Token is automatically stored in cookie
  // Subsequent requests will include auth_token
} else {
  console.error('[Auth] Login failed');
}

API Endpoint

Makes a POST request to:
{NEXT_PUBLIC_BACKEND_API_URL}/api/autenticacion/iniciar-sesion

Request Body

{
  "email": "tecnico@test.com",
  "password": "12345678"
}

Expected Backend Response

{
  "estado": "exito",
  "data": {
    "token": "1|abcdefghijklmnopqrstuvwxyz1234567890"
  }
}

getAuthToken

Retrieves the stored authentication token from cookies.
export async function getAuthToken(): Promise<string | undefined>

Response

return
string | undefined
Returns the token value if present, or undefined if not found

Example

const token = await getAuthToken();

if (token) {
  // Use token for authenticated requests
  const response = await fetch(`${backendUrl}/api/protected-route`, {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });
} else {
  // User not authenticated, redirect to login
  console.log('No auth token found');
}

Use Cases

  1. API Requests: Include token in Authorization headers
  2. Session Validation: Check if user is authenticated
  3. Middleware: Verify authentication in Next.js middleware
  4. Server Components: Access auth state in React Server Components

Configuration

Environment Variables

NEXT_PUBLIC_BACKEND_API_URL
string
default:"https://gima-backend.test"
Base URL of the Laravel backend API
NODE_ENV
string
Node environment. When set to development, disables TLS certificate validation

Development Mode

In development (NODE_ENV === 'development'), the module automatically:
  • Disables TLS certificate validation (NODE_TLS_REJECT_UNAUTHORIZED = '0')
  • Sets secure: false on cookies for HTTP testing
  • Enables verbose console logging
TLS validation bypass should NEVER be used in production environments

Security Considerations

Current Implementation (Development)

  • ✅ HTTP-only cookies prevent XSS token theft
  • ✅ SameSite=lax provides CSRF protection
  • ⚠️ Hardcoded credentials (not for production)
  • ⚠️ TLS validation disabled in development

Production Recommendations

Implement proper authentication flows:
export async function login(
  email: string, 
  password: string
): Promise<string | null> {
  const response = await fetch(`${backendUrl}/api/autenticacion/iniciar-sesion`, {
    method: 'POST',
    body: JSON.stringify({ email, password })
  });
  // ... handle response
}
Remove or conditionally disable the TLS bypass:
// Only for local development with self-signed certs
if (process.env.NODE_ENV === 'development' && 
    process.env.ALLOW_SELF_SIGNED === 'true') {
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
}
Implement token refresh logic:
export async function refreshToken(): Promise<string | null> {
  const currentToken = await getAuthToken();
  if (!currentToken) return null;
  
  const response = await fetch(`${backendUrl}/api/refresh`, {
    headers: { 'Authorization': `Bearer ${currentToken}` }
  });
  // ... handle refresh
}
export async function logout(): Promise<void> {
  const token = await getAuthToken();
  if (token) {
    await fetch(`${backendUrl}/api/logout`, {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${token}` }
    });
  }
  
  // Clear cookie
  const cookieStore = await cookies();
  cookieStore.delete('auth_token');
}

Integration Example

Complete authentication flow:
// app/api/auth/route.ts
import { loginSilent, getAuthToken } from '@/app/actions/auth';

export async function GET() {
  const existingToken = await getAuthToken();
  
  if (existingToken) {
    return Response.json({ authenticated: true });
  }
  
  const token = await loginSilent();
  
  if (token) {
    return Response.json({ authenticated: true, token });
  }
  
  return Response.json({ authenticated: false }, { status: 401 });
}
// app/components/ProtectedComponent.tsx
import { getAuthToken } from '@/app/actions/auth';

export default async function ProtectedComponent() {
  const token = await getAuthToken();
  
  if (!token) {
    redirect('/login');
  }
  
  // Fetch protected data
  const data = await fetch(`${process.env.NEXT_PUBLIC_BACKEND_API_URL}/api/data`, {
    headers: { 'Authorization': `Bearer ${token}` }
  });
  
  return <div>{/* Render protected content */}</div>;
}

Error Handling

The loginSilent function handles errors gracefully:

HTTP Errors

if (!response.ok) {
  const errorText = await response.text();
  console.error(`[Auth] Error de login (${response.status}):`, errorText);
  return null;
}

Network Errors

try {
  // ... authentication logic
} catch (error) {
  console.error('[Auth] Excepción en loginSilent:', error);
  return null;
}

Response Validation

if (data.estado === 'exito' && data.data?.token) {
  // Success
} else {
  console.error('[Auth] Respuesta de login inesperada:', data);
  return null;
}

Build docs developers (and LLMs) love