Especificación de claves API de usuario

Encuentro que el valor predeterminado de allowed_user_api_auth_redirects como “discourse://auth_redirect” es bastante restrictivo, especialmente porque “discourse” no parece ser un esquema de URI válido.

Por favor, expliquen el razonamiento detrás de este valor predeterminado. Gracias.

Yo también tengo este problema. Si inicio la API desde una aplicación JS, automáticamente los encabezados permitidos son: User-Api-Key, User-Api-Client-Id, aunque no necesito claves de API de usuario. Todo lo que quiero es una clave de API simple, pero no logro que nada funcione. Si intento pasar Api-Key en los encabezados, obtengo un error de CORS porque espera User-Api-Key. Pero cuando intento usar User-Api-Key, obtengo errores 403. Estoy atascado. Pensaría que este es el uso básico para utilizar las APIs. No estoy intentando hacer nada fuera de lo común. Simplemente estoy tratando de crear una nueva publicación en un tema.

2 Me gusta

Ese es el esquema de URI personalizado utilizado por la aplicación DiscourseHub para iOS y Android.

6 Me gusta

Tengo una pregunta sobre los “tokens de lectura” y los “tokens de escritura”. Este comentario es de 2016, ¿es posible que ya haya sido modificado? ¿O los valores predeterminados siguen siendo solo “tokens de lectura”?

Antecedentes: Soy uno de los desarrolladores de un sistema de redes sociales distribuido. Ya tenemos conectores para sistemas que no son federados. La idea es crear también un complemento para Discourse. Pero, dado que es probable que la mayoría de los sistemas no permitan a los usuarios generar tokens que permitan publicar, intentaremos otro enfoque. Ya contamos con un conector de correo. Entonces, simplemente utilizaremos la función de listas de correo de Discourse, intentaremos mejorar el contenido devuelto y publicaremos mediante SMTP.

Puedes escribir tokens si solicitas el ámbito de antemano

3 Me gusta

Por supuesto, esto siempre es posible. Pero tengo la sensación de que esto se convertiría en una pesadilla para el soporte. Nuestro software tiene varias cientos de instalaciones con (en total) más de 10.000 usuarios. Cuando vean que existe un complemento que se conecta a Discourse, muchos seguramente querrán usarlo. Y como lo más probable es que no funcione de inmediato, esto generará preguntas y trabajo de soporte de nuestra parte. Además, generará trabajo para los administradores de las diversas instalaciones de Discourse. Y es muy probable que no todos lo permitan, lo cual causará frustración.

Por lo tanto, posiblemente al principio me centraré en integrar los correos del modo de lista de correo. ¿O es posible combinar estas dos cosas? Es decir: leer las publicaciones a través de la API, pero publicarlas mediante SMTP?

Hola… no sé cómo generar la public_key. ¿Debería usar un generador de RSA para obtener la clave pública/privada?
Si es así, ya he usado algunos generadores de RSA en línea, pero obtengo este error:

OpenSSL::PKey::RSAError (Ni clave PUB ni PRIV: error asn1 anidado) /var/www/discourse/app/controllers/user_api_keys_controller.rb:189:in `initialize'

También quiero preguntarles si esto se ajusta a mi caso de uso:
Tengo una aplicación y básicamente quiero autenticar al usuario y obtener el nombre de usuario. ¿Es el flujo de generación de claves API el más sencillo para validar el inicio de sesión del usuario en mi aplicación? Si es posible, quiero evitar SSO porque parece más complicado.

Yo también estoy en la misma situación, aunque solo estoy intentando usar User-Api-Key (no Api-Key) para crear una publicación en un tema y estoy recibiendo una denegación CSRF por parte de la biblioteca actionpack.

A menos que el servidor de Discourse haya desactivado la verificación CSRF, publicar desde una aplicación de escritorio de terceros parece difícil. No voy a emular un navegador.

@sam ¿Qué opinas sobre permitir que las claves de API de usuario que solo tienen el alcance read se pasen mediante parámetros de URL en las solicitudes GET?

El caso de uso es permitir integraciones como suscribir tus Marcadores mejorados con recordatorios en Google Calendar usando claves de API de usuario.

5 Me gusta

¿Qué tal si creamos un nuevo ámbito específico, con un tercer parámetro para indicar ‘parámetro de consulta permitido’? De esta manera, la gente no podrá abusar de él para otros fines (por ejemplo, eludir CORS y solicitar la API de Discourse desde otro sitio).

(desde aquí)

SCOPES = {
    read: [:get],
    write: [:get, :post, :patch, :put, :delete],
    message_bus: [[:post, 'message_bus']],
    push: nil,
    one_time_password: nil,
    notifications: [[:post, 'message_bus'], [:get, 'notifications#index'], [:put, 'notifications#mark_read']],
    session_info: [
      [:get, 'session#current'],
      [:get, 'users#topic_tracking_state'],
      [:get, 'list#unread'],
      [:get, 'list#new'],
      [:get, 'list#latest']
    ],
+   calendar: [ [:get, 'users#bookmarks_cal', true ] ],
  }

(A parte: ¿por qué estamos usando arrays anidados aquí…)

10 Me gusta

Me gusta que la clave de API se marque explícitamente como «permitida en GET» a nivel de usuario.

En general, la opción podría estar abierta para cualquier solicitud GET. La regla que me gusta es que, al operar en este modo:

  1. La clave de API del usuario esté 100% restringida a una única acción de controlador GET específica.
  2. La clave de API del usuario se marque como permitida en los parámetros de consulta GET.

Esto limita el impacto de cualquier fuga aquí a través de un proxy, ya que la clave nunca se reutilizará.

Supongo que {get: 'list#new'}, {get: 'list#latest'} también funcionaría.

7 Me gusta

Estoy muy interesado en las claves de API de usuario del tipo get param only. Mi pregunta es: ¿tienen previsto permitir que los usuarios generen estas claves a través de la interfaz gráfica?

Probablemente, quizás detrás de una configuración del sitio o con un complemento. Tenemos previsto normalizar un poco el conjunto de funciones para que las claves de API de administración también admitan ámbitos.

4 Me gusta

Hola… ¿Puedes resolver este problema? Tengo el mismo problema y no puedo solucionarlo. Probé pasando diferentes tipos de claves y nada funcionó. Cualquier ayuda sería muy apreciada.

¿Hay alguna biblioteca para esto? Si no, ¿alguna implementación de ejemplo? Estoy intentando usar PHP para identificar la cuenta de Discourse de un usuario en una parte separada del sitio web. Esto parece un flujo de OAuth modificado, pero estoy un poco confundido sobre cómo implementarlo.

Específicamente, no estoy seguro de cómo hacer toda la generación de claves pública/privada.

¿Hay alguna manera de usar simplemente OAuth 2 con Discourse como proveedor de OAuth?

2 Me gusta

¿Lo lograste usando la User-Api-Key? Yo también estoy recibiendo el mensaje «You are not permitted to view the requested resource».

1 me gusta

He descubierto qué hice mal: la carga útil devuelta no es la clave de la API de UserAPI en sí, sino una cadena JSON cifrada que debe descifrarse con la clave privada del par de claves pública/privada.

2 Me gusta

EDIT: He logrado que la mayor parte funcione y proporcionaré una descripción una vez que esté completamente operativo.


¿Cómo obtiene el cliente el par de claves privada/pública y el ID?

¿Podrías proporcionar código para obtener la clave de API de usuario con una aplicación de JavaScript? (Una aplicación de JavaScript que intenta permitir a un usuario realizar llamadas a la API de un foro de Discourse).

Estoy recibiendo errores 403. O, un error que dice: Lo sentimos, no podemos emitir claves de API de usuario; esta función puede estar deshabilitada por el administrador del sitio (aunque mi sitio ha marcado: Permitir la generación de claves de API de usuario).

Creo que el problema podría ser cómo generar el par de claves privada/pública (¿cómo se hace eso?) y luego manejar la redirección.

Agradezco cualquier código.

Lo he logrado hacer funcionar, tras varios intentos y errores.

Estos son los pasos básicos que sigo cuando tengo una aplicación independiente que he programado y quiero que los usuarios puedan usarla para realizar llamadas a la API de un sitio de Discourse.

Para ello, necesito generar un token de API por usuario para realizar llamadas en nombre de cada usuario específico (al menos en un entorno de Node.js/JavaScript).


Tenga en cuenta que, para la parte de JavaScript, encontré que el código proporcionado por @KengoTODA aquí: discourse-api-key-generator/src/index.ts at main · KengoTODA/discourse-api-key-generator · GitHub fue de gran ayuda.


Estos son los pasos que he seguido:

Primero: Generar un par de claves pública y privada.

Esto es algo que su aplicación debe generar: una clave pública y una privada. El gist de GitHub proporciona un método para hacerlo.

Segundo: Tener una URL de redirección.

Esta es la URL a la que Discourse redirigirá, proporcionando el token de API final en la carga útil (payload). Si tiene una aplicación de escritorio (es decir, no tiene una URL de navegador), la URL de redirección se basará en un protocolo personalizado que configure para abrir la aplicación cuando se ingrese la URL de redirección en el navegador.

Tenga en cuenta que la URL de redirección debe estar en la lista blanca en la configuración del sitio del sitio de Discourse de destino.

El sitio de Discourse también probablemente necesite tener activada la configuración del sitio para “Permitir claves de API de usuario”. Consulte la publicación original sobre este tema para obtener detalles sobre “Configuración del sitio”.

Tercero: Enviar la llamada de solicitud de API a la URL de solicitud de Discourse.

Su aplicación enviará una llamada a una URL que sigue este formato:

https://[su sitio de Discourse de destino .com]/user-api-key-new"

y agregando como parámetros:

  • el nombre de su aplicación
  • su “client_id” (pude usar hostname(), desde const {hostname} = require('os') para una aplicación de escritorio, al igual que en el gist de GitHub mencionado anteriormente)
  • ámbitos (scopes) (estos son los ámbitos que desea que el usuario pueda utilizar a través de la API, como “write”, “read”, etc.)
  • su clave pública (del paso 1 anterior)
  • su URL de redirección (del paso 2 anterior)
  • nonce (este es un valor que puede elegir; por ejemplo, usar simplemente ‘1’ parece funcionar)

Cuarto: El usuario autoriza su aplicación en la página del sitio de Discourse que se abre mediante la URL de solicitud

Cuando envíe la URL de solicitud correctamente, se abrirá una página en el sitio de Discourse informando al usuario que su aplicación desea acceder al sitio.

En esa página, hay un botón para que el usuario permita esto. Cuando el usuario hace clic en este botón, el sitio de Discourse redirige a la URL de redirección que proporcionó y adjunta como parámetro un ?payload=[LA CLAVE DE API]. La CLAVE DE API aquí es la clave que necesita decodificar en su aplicación.

Quinto: Su aplicación captura el valor de la URL de redirección (con el valor de carga útil) y decodifica la CLAVE DE API

Casi ha terminado. Su aplicación debe analizar la URL de redirección a la que fue Discourse y obtener la clave de API contenida en la carga útil.

Una vez que tenga esa clave de API, debe hacer dos cosas:

  1. Obtener la clave real, no la versión codificada en URL: si está obteniendo un parámetro de una URL, a menudo está codificada en URL (agregando % aquí y allá, etc.). Necesita limpiarla. En JavaScript, he encontrado que decodeURIComponent funciona para esto.
  2. Una vez que tenga la CLAVE DE API limpiada devuelta por Discourse, debe decodificarla. Para ello, puede usar la decodificación de JavaScript con claves privadas. Básicamente, usa su clave privada (generada en el primer paso anterior) para decodificar la CLAVE DE API limpiada. Hay algún ejemplo de JavaScript en el gist de GitHub que mencioné anteriormente: discourse-api-key-generator/src/index.ts at main · KengoTODA/discourse-api-key-generator · GitHub

Después de ejecutar su código de decodificación, tiene el token en sí, que ahora puede usar para realizar llamadas de API autenticadas en nombre del usuario.

Sexto: Usar el token (es decir, la clave de API final, limpiada y decodificada) para realizar llamadas a la API en nombre del usuario

Con ese token, parece que no necesita ingresar el nombre de usuario en la llamada a la API. Encuentro que la siguiente cabecera es suficiente cuando la incluye en su llamada GET, POST, PUT, etc.:

headers: {
"User-Api-Key": [el token]
}

Y con eso, espero que tenga un método de autenticación por usuario funcional para interactuar con Discourse.

7 Me gusta

¿Cuáles son las implicaciones de seguridad de agregar elementos a allowed_user_api_auth_redirects? Tengo a alguien pidiendo agregar una cadena para admitir la integración con NextCloud.

1 me gusta