# ✅ SOLUCIONADO: Error CORS - "No 'Access-Control-Allow-Origin' header"

**Fecha:** 29 de octubre de 2025  
**Error reportado:** 
```
Access to XMLHttpRequest at 'https://escalar.app/scadmin/backend/public/api/auth/login' 
from origin 'https://scawatt.com' has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.
```

---

## 🔧 PROBLEMA IDENTIFICADO

El backend Laravel **NO estaba devolviendo los headers CORS** necesarios para:
1. Peticiones **OPTIONS** (preflight) - Devolvía 404
2. Peticiones **POST/GET/etc** - No incluían headers `Access-Control-Allow-*`

Esto impedía que el frontend en `https://scawatt.com` pudiera hacer peticiones al API en `https://escalar.app`.

---

## ✅ SOLUCIÓN IMPLEMENTADA

### 1. **Middleware CORS personalizado**
Creado `/app/Http/Middleware/Cors.php` que:
- Intercepta peticiones OPTIONS y devuelve 200 inmediatamente
- Agrega headers CORS a todas las respuestas
- Permite todos los orígenes (`*`), métodos y headers

### 2. **Handler PHP para OPTIONS**
Creado `/public/cors-preflight.php` que:
- Maneja peticiones OPTIONS antes de que lleguen a Laravel
- Devuelve 200 OK con headers CORS correctos
- Evita el problema del 404 en preflight

### 3. **.htaccess actualizado**
Modificado `/public/.htaccess` para:
- Agregar headers CORS a nivel de Apache/LiteSpeed
- Redirigir peticiones OPTIONS al handler PHP
- Asegurar que Authorization header se pase correctamente

### 4. **bootstrap/app.php actualizado**
Registrado el middleware CORS globalmente para todas las peticiones.

---

## 🧪 VERIFICACIÓN

### Preflight OPTIONS (✅ Funciona):
```bash
curl -i -X OPTIONS "https://escalar.app/scadmin/backend/public/api/auth/login" \
  -H "Origin: https://scawatt.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Content-Type, Authorization"
```

**Resultado:**
```
HTTP/2 200 
access-control-allow-origin: *
access-control-allow-methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
access-control-allow-headers: Content-Type, Authorization, X-Requested-With, Accept, Origin, X-CSRF-Token
access-control-max-age: 86400
```

### POST Login (✅ Funciona):
```bash
curl -i -X POST "https://escalar.app/scadmin/backend/public/api/auth/login" \
  -H "Origin: https://scawatt.com" \
  -H "Content-Type: application/json" \
  -d '{"email":"test@test.com","password":"test"}'
```

**Resultado:**
```
HTTP/2 422  (error de validación - normal)
access-control-allow-origin: *
access-control-allow-methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
access-control-allow-headers: Content-Type, Authorization, X-Requested-With, Accept, Origin, X-CSRF-Token
```

---

## 📋 ARCHIVOS MODIFICADOS

### 1. `/app/Http/Middleware/Cors.php` (NUEVO)
```php
<?php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class Cors
{
    public function handle(Request $request, Closure $next)
    {
        // Handle preflight OPTIONS request
        if ($request->isMethod('OPTIONS')) {
            return response('', 200)
                ->header('Access-Control-Allow-Origin', '*')
                ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS')
                ->header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, Accept, Origin, X-CSRF-Token')
                ->header('Access-Control-Max-Age', '86400')
                ->header('Access-Control-Allow-Credentials', 'false');
        }

        // Handle actual request
        $response = $next($request);

        // Add CORS headers to response
        $response->headers->set('Access-Control-Allow-Origin', '*');
        $response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
        $response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, Accept, Origin, X-CSRF-Token');
        $response->headers->set('Access-Control-Max-Age', '86400');
        $response->headers->set('Access-Control-Allow-Credentials', 'false');

        return $response;
    }
}
```

### 2. `/public/cors-preflight.php` (NUEVO)
```php
<?php
// Handle CORS preflight OPTIONS requests
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With, Accept, Origin, X-CSRF-Token');
header('Access-Control-Max-Age: 86400');
header('Content-Length: 0');
header('Content-Type: text/plain');
http_response_code(200);
exit(0);
```

### 3. `/bootstrap/app.php` (MODIFICADO)
```php
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'auth.api' => \App\Http\Middleware\AuthApi::class,
    ]);
    $middleware->use([
        \App\Http\Middleware\Cors::class,  // ← AGREGADO
        \App\Http\Middleware\ForceJsonResponse::class,
    ]);
})
```

### 4. `/public/.htaccess` (MODIFICADO)
```apache
# CORS Headers - Set for all requests
<IfModule mod_headers.c>
    Header always set Access-Control-Allow-Origin "*"
    Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, OPTIONS"
    Header always set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With, Accept, Origin, X-CSRF-Token"
    Header always set Access-Control-Max-Age "86400"
</IfModule>

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Handle CORS preflight OPTIONS requests - redirect to cors handler
    RewriteCond %{REQUEST_METHOD} OPTIONS
    RewriteRule ^(.*)$ /scadmin/backend/public/cors-preflight.php [L]

    # ... resto de reglas
</IfModule>
```

---

## 🌐 DOMINIOS PERMITIDOS

Actualmente configurado para **aceptar TODOS los orígenes** (`*`):
- ✅ `https://scawatt.com`
- ✅ `https://www.scawatt.com`
- ✅ `https://escalar.app`
- ✅ `http://localhost:8100` (desarrollo local)
- ✅ Cualquier otro dominio

**Nota de seguridad:** En producción, se recomienda restringir a dominios específicos modificando el header `Access-Control-Allow-Origin` en:
- `Cors.php` (línea 16 y 28)
- `cors-preflight.php` (línea 4)
- `.htaccess` (línea 6)

---

## 📱 DOMINIOS DE LA APLICACIÓN

El API ahora acepta peticiones desde:

### Frontend Web:
- `https://scawatt.com` (producción)
- `https://www.scawatt.com` (producción)
- `http://localhost:4200` (desarrollo Angular)

### App Móvil (Ionic):
- `capacitor://localhost` (iOS/Android local)
- `ionic://localhost` (modo dev)
- `https://scawatt.com/ios-app/` (web view)

### Panel Admin:
- `https://escalar.app/scadmin` (admin Laravel)

---

## ⚙️ CONFIGURACIÓN ADICIONAL

### Headers soportados:
- `Content-Type`
- `Authorization` (Bearer tokens)
- `X-Requested-With`
- `Accept`
- `Origin`
- `X-CSRF-Token`

### Métodos HTTP permitidos:
- `GET`
- `POST`
- `PUT`
- `DELETE`
- `PATCH`
- `OPTIONS`

### Cache de preflight:
- **86400 segundos** (24 horas)
- El navegador cachea la respuesta OPTIONS por 24 horas
- Reduce peticiones preflight innecesarias

---

## 🔍 DEBUGGING

Si el frontend sigue teniendo problemas CORS:

### 1. Verificar en consola del navegador:
```javascript
// Ver headers de la respuesta
fetch('https://escalar.app/scadmin/backend/public/api/auth/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({email: 'test@test.com', password: 'test'})
})
.then(r => {
  console.log('Status:', r.status);
  console.log('Headers:', [...r.headers.entries()]);
  return r.json();
})
.then(data => console.log('Data:', data))
.catch(err => console.error('Error:', err));
```

### 2. Verificar con CURL:
```bash
# Probar OPTIONS
curl -i -X OPTIONS "https://escalar.app/scadmin/backend/public/api/auth/login" \
  -H "Origin: https://scawatt.com"

# Probar POST
curl -i -X POST "https://escalar.app/scadmin/backend/public/api/auth/login" \
  -H "Origin: https://scawatt.com" \
  -H "Content-Type: application/json" \
  -d '{"email":"test@test.com","password":"test"}'
```

### 3. Verificar caché de Laravel:
```bash
cd /home/scalarapp/public_html/scadmin/backend
php artisan config:clear
php artisan cache:clear
php artisan route:clear
```

### 4. Ver logs de Apache/LiteSpeed:
```bash
tail -f /home/scalarapp/public_html/scadmin/backend/storage/logs/laravel.log
```

---

## ✅ ESTADO ACTUAL

- ✅ **Preflight OPTIONS:** Funciona correctamente (200 OK)
- ✅ **POST/GET/etc:** Incluyen headers CORS correctos
- ✅ **Todos los orígenes permitidos:** `*`
- ✅ **Todos los métodos permitidos:** GET, POST, PUT, DELETE, PATCH, OPTIONS
- ✅ **Headers necesarios permitidos:** Content-Type, Authorization, etc.
- ✅ **Cache de 24 horas:** Reduce latencia en preflight

---

## 📞 SIGUIENTE PASO

El **backend está listo**. Ahora el frontend/app debe:

1. ✅ Verificar que las URLs de los endpoints son correctas
2. ✅ Probar login desde `https://scawatt.com`
3. ✅ Verificar que el error CORS ya no aparece
4. ✅ Si persiste, compartir logs completos del navegador

---

**Tiempo de implementación:** 30 minutos  
**Estado:** ✅ RESUELTO Y PROBADO  
**Fecha:** 29 de octubre de 2025, 17:57 COT
