Error de CORS al acceder a la API desde una aplicación de JavaScript

Esta sería una buena respuesta para mí, excepto por que no puedo hacer que la autenticación basada en encabezados funcione, así que estoy intentando hacerlo con formularios y también estoy teniendo problemas con CSRF. ¿Alguna solución? Estoy intentando crear un nuevo tema usando la API.

Necesitaremos más información para poder ayudarte. ¿Podrías compartir un fragmento de código que muestre cómo estás intentando utilizar la autenticación basada en encabezados?

El problema que he estado teniendo se debe principalmente a que, cada vez que intento hacer una llamada con autenticación basada en encabezados, los encabezados aceptados son siempre “User-Api-Key” y “User-Client-Id” en lugar de “Api-Key” y “Api-Username”, por lo que obtengo errores de CORS. No creo que necesite claves basadas en usuarios. Solo estoy intentando realizar una solicitud autenticada sencilla para crear un nuevo tema. Si intento usar “User-Api-Key”, obtengo errores 403.

Este es un código de ejemplo (Angular TypeScript), pero debería ser similar a otras configuraciones:

    createNewTopic(postBody: any) {
        let url = "myserver.com/posts.json";
        let CATEGORY_ARTICLES = 6;
        let topicContent = `
          <p>Alguno contenido
        </p>
        <p>¿Funcionó eso?</p>
        `;
        let post = {
          "title": "Tdk Test 1",
          "raw": topicContent,
          "category": CATEGORY_ARTICLES,
          "target_usernames": "tdekoekkoek",
          "archetype": "",
          "created_at": new Date()
        }
        let headers = new HttpHeaders()
          .set("Accept", "application/json")
          .set("User-Api-Key", DISCOURSE_API_KEY)
          .set("User-Key", "system")
          .set("Content-Type", "application/x-www-form-urlencoded")
        let options = {headers: headers};
        return this.http.post(url, post, options);
      }

user-api-key y user-client-id son un método de autenticación completamente diferente. Las claves API regulares no funcionarán con esas cabeceras. ¿Qué sucede cuando usas los nombres de cabecera correctos? (api-key y api-username)

Recibo un error de CORS porque el servidor espera el encabezado User-Api-Key. Reviso los encabezados esperados en la respuesta OPTIONS y eso es exactamente lo que indica. Hay un tema similar en otro lugar de este foro donde un usuario experimentaba esto al llamar desde una aplicación de JavaScript.

¡Oh, así que estás intentando hacer esta solicitud desde una aplicación de JavaScript del lado del cliente! Eso no está permitido por varias razones. Por ejemplo, si incluyes una clave de API de administrador en el código fuente de tu aplicación de JavaScript, cualquier usuario podría obtener acceso completo de administrador a tu foro. Aquí hay un tema anterior sobre el asunto.

Sí, eso es lo que estoy intentando hacer. Eso debería estar documentado con mayor claridad. Esa ha sido toda mi estrategia desde que comencé con Discourse. Agradezco tu ayuda. He estado luchando con esto durante días y leyendo la documentación. Tendré que replantear todo mi enfoque, ya que actualmente estoy construyendo una aplicación sin servidor, aunque sí tengo acceso a un servidor de Node.js.

Esto no es una restricción específica de Discourse; en general, es una mala práctica incluir credenciales de administrador en el código fuente de un sitio web.

Si puedes realizar la llamada a la API de Discourse desde tu servidor de Node.js, esa sería probablemente la mejor solución. Si necesitas que tu aplicación sea puramente del lado del cliente, entonces solicitar claves de API específicas del usuario es una opción, aunque su configuración es mucho más compleja: User API keys specification

Honestamente, acceder a APIs desde aplicaciones cliente con CORS habilitado es extremadamente común y estándar. No puedo creer que no exista una forma más segura de hacerlo. Toda una industria gira en torno a APIs alojadas que se acceden desde diferentes dominios. En cuanto al acceso con una API de usuario, he visto cómo crearlas, pero no tengo claro cuáles son las credenciales reales. Siempre obtengo un error 403 de permiso denegado al usar ese método.

Creo que me encuentro en una situación similar.

Un poco sobre el caso de uso:

Utilizo Discourse como backend y construyo el frontend en VueJS. Tengo la intención de usar únicamente la API REST. Para cada usuario de nuestra plataforma, he creado una clave de API de usuario y utilizo ambas cabeceras (Api-Key y Api-Username) para la autenticación.

Cada usuario se autentica de forma segura con nuestros servidores y luego recibe su token de Discourse para la autenticación. A continuación, deseamos usar este token (en un frontend VueJS) para enviar solicitudes a la API (publicar temas, publicaciones, editar, etc.).

Nada está codificado de forma rígida; todos los tokens se reciben tras una autenticación adecuada.

El problema:
Recibo un mensaje de error de CORS, aunque lo he habilitado en app.yml y lo he configurado en la sección de Seguridad de la configuración de administrador.

El error: El campo de cabecera de la solicitud api-key no está permitido por Access-Control-Allow-Headers

¿Estoy experimentando el mensaje de error de CORS por la misma razón? ¿Por qué se bloquean las solicitudes CORS al utilizar las cabeceras “Api-Key” y “Api-Username”? Debo estar malinterpretando su caso de uso.

EDITO:
Tengo una teoría sobre mi malentendido. Cuando creo una clave de API de usuario desde el endpoint “Generate an api_key for a user” de la API REST, ¿tiene esa clave permisos administrativos? ¿No es simplemente una clave de usuario para publicar y comentar? Si es así, entonces entiendo la restricción.

Por favor, corrígeme si es necesario.

@david ¿no podría Discourse simplemente hacer que el servidor firme un secreto de sesión con un HMAC, y este secreto de sesión, a su vez, podría usarse para firmar cosas en la sesión dada? Si se roba, entonces presumiblemente la cookie de sesión o el nonce CSRF tampoco lo harían. Es un poco como una cadena de certificados: no tienes que poner la clave raíz en el navegador.

Estos son solo para la API de administración. La forma en que lo entendí es que para los clientes de JavaScript necesitas, como se mencionó anteriormente, consultar User API keys specification .