Skip to content
MaytokVerso
Atrás

Solucionando el error de API 'You need to sign in or sign up' de Chatwoot en CapRover

Contexto

Me encontré con un error persistente de autenticación de API al ejecutar Chatwoot en una implementación de CapRover. Mi objetivo era usar el API de Chatwoot para automatizar flujos de trabajo de mensajería. Sin embargo, cada solicitud de API que enviaba desde cualquier fuente, incluso desde curl, fallaba, a pesar de usar el api_access_token correcto.

Tras investigar, sospeché que el problema no estaba en Chatwoot en sí ni en mis credenciales, sino en el proxy inverso Nginx que CapRover utiliza para gestionar el tráfico entrante.

El Problema

Todas las solicitudes de API a la instancia de Chatwoot fallaban con un estado 401 Unauthorized y la siguiente respuesta de error en JSON:

{
  "error": "You need to sign in or sign up before continuing."
}

Esto indicaba que la aplicación Chatwoot no estaba recibiendo los encabezados (headers) de autenticación correctamente. El problema radicaba en el comportamiento predeterminado de Nginx, que elimina silenciosamente los encabezados que contienen guiones bajos (_), una convención de la que depende la API de Chatwoot para sus tokens.

Entorno

Solución

La solución consiste en personalizar la configuración de Nginx para la aplicación Chatwoot dentro de CapRover para permitir explícitamente encabezados con guiones bajos. Esto asegura que el api_access_token llegue a la aplicación Chatwoot.

Pasos a seguir

  1. Accede al Dashboard de CapRover: Inicia sesión en tu instancia de CapRover.

  2. Navega a la Aplicación de Chatwoot: Ve a la sección Apps y selecciona tu aplicación chatwoot-web.

  3. Edita la Configuración de Nginx: Dirígete a la pestaña HTTP Settings y busca el área de texto Custom Nginx Config.

  4. Añade la directiva underscores_in_headers: Debes añadir una sola línea al bloque server principal. Un buen lugar es justo después de la directiva server_name.

Aquí tienes la configuración de Nginx completa y modificada. Puedes reemplazar todo el contenido del área de texto con el bloque de abajo:

<%
if (s.forceSsl) {
%>
    server {

        listen       80;

        server_name  <%-s.publicDomain%>;

        # Usado por Lets Encrypt
        location /.well-known/acme-challenge/ {
            root <%-s.staticWebRoot%>;
        }

        # Usado por CapRover para health check
        location /.well-known/captain-identifier {
            root <%-s.staticWebRoot%>;
        }

        location / {
            return 302 https://$http_host$request_uri;
        }
    }
<%
}
%>


server {

    <%
    if (!s.forceSsl) {
    %>
        listen       80;
    <%
    }
    if (s.hasSsl) {
    %>
        listen              443 ssl;
        http2               on;
        ssl_certificate     <%-s.crtPath%>;
        ssl_certificate_key <%-s.keyPath%>;
    <%
    }
    if (s.logAccessPath) {
    %>
        access_log <%-s.logAccessPath%>;
    <%
    }
    %>

        client_max_body_size 500m;

        server_name  <%-s.publicDomain%>;

        # <<< ESTA ES LA SOLUCIÓN >>>
        # Permitir encabezados con guiones bajos para la API de Chatwoot (ej. api_access_token)
        underscores_in_headers on;

        resolver 127.0.0.11 valid=10s;
        set $upstream http://<%-s.localDomain%>:<%-s.containerHttpPort%>;

        location / {


    <%
    if (s.redirectToPath) {
    %>
        return 302 <%-s.redirectToPath%>$request_uri;
    <%
    } else {
    %>

        <%
        if (s.httpBasicAuthPath) {
        %>
            auth_basic           "Restricted Access";
            auth_basic_user_file <%-s.httpBasicAuthPath%>; 
        <%
        }
        %>

            proxy_pass $upstream;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

        <%
        if (s.websocketSupport) {
        %>
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_http_version 1.1;
        <%
        }
        %>
    
    
    <%
    }
    %>
    
        }

        # Usado por Lets Encrypt
        location /.well-known/acme-challenge/ {
            root <%-s.staticWebRoot%>;
        }
        
        # Usado por CapRover para health check
        location /.well-known/captain-identifier {
            root <%-s.staticWebRoot%>;
        }

        error_page 502 /captain_502_custom_error_page.html;
        location = /captain_502_custom_error_page.html {
                root <%-s.customErrorPagesDirectory%>;
                internal;
        }
}
  1. Guardar y Actualizar: Haz clic en el botón Save & Update. CapRover validará y desplegará la nueva configuración, reiniciando la aplicación.

  2. Prueba la Conexión de la API: Vuelve a ejecutar tu solicitud de API. El error 401 Unauthorized debería haber desaparecido y la conexión debería funcionar como se espera.

¿Por qué funciona esto?

El problema es un conflicto entre la política de seguridad predeterminada de Nginx y el diseño de la API de Chatwoot.

Al añadir la directiva underscores_in_headers on;, anulamos el comportamiento predeterminado de Nginx y le indicamos que pase estos encabezados a la aplicación Chatwoot. Una vez que la aplicación recibe el token correcto, puede autenticar la solicitud con éxito.

Notas Adicionales

Este es un problema común para otras aplicaciones desplegadas detrás de Nginx, no solo para Chatwoot. Si te enfrentas a errores de autenticación de API inexplicables, verificar cómo el proxy maneja los encabezados es un buen paso de depuración.

Esta corrección debe aplicarse a la aplicación chatwoot-web, que es el punto de entrada público, y no a la aplicación chatwoot-worker.

Conclusión

Este pequeño ajuste en Nginx resolvió por completo el problema de autenticación de la API para mi instancia de Chatwoot en CapRover. Espero que esta guía detallada ahorre a otros la frustración de depurar este problema.

¡Feliz automatización!


Comparte este post en:

Next Post
Experimientos con la API Graph de Meta