Especificación de claves API de usuario

Discourse contiene un sistema para generar claves de API por usuario si se sigue un protocolo muy específico. Esta característica facilita el acceso de “aplicaciones” a las instancias de Discourse sin necesidad de involucrar a los moderadores.

Descripción general

A grandes rasgos:

  1. El cliente (aplicación de escritorio, complemento de navegador, aplicación móvil) genera un par de claves pública/privada y una URL de retorno
  2. El cliente redirige a una ruta en Discourse proporcionándole su clave pública a Discourse
  3. Discourse obtiene la aprobación del usuario para usar la aplicación
  4. Discourse genera una clave de API de usuario
  5. Discourse redirige de vuelta a la URL de retorno con una carga útil cifrada usando la clave pública que contiene la clave de API del usuario

Detalles

Casos de uso:

  1. Aplicaciones de escritorio que consultan sitios de Discourse en nombre de los usuarios finales para obtener recuentos de notificaciones en múltiples sitios.

  2. Aplicaciones móviles que consultan sitios de Discourse en nombre de los usuarios finales y gestionan notificaciones push.

  3. Aplicaciones web que proporcionan un panel de control para los usuarios finales sobre varios sitios de Discourse.

  4. Integraciones personalizadas con aplicaciones de terceros que consumen Discourse como parte de una aplicación corporativa general. Por ejemplo: integrar notificaciones de la comunidad de Discourse en la aplicación hopscotch.

El diseño:

Ajustes del sitio

  • allow_user_api_key_scopes: ámbitos de acceso permitidos para las claves de API de usuario. Los ámbitos se definen aquí. Los ámbitos integrados disponibles son: read, write, message_bus, push, one_time_password, notifications, session_info, bookmarks_calendar, user_status (los complementos pueden registrar ámbitos adicionales).

  • user_api_key_allowed_groups: controla qué grupos están autorizados a generar claves de API de usuario (por defecto: administradores, moderadores y trust_level_0)

  • allowed_user_api_push_urls: lista de sitios que pueden ser destinos para notificaciones push

  • allowed_user_api_auth_redirects: destinos de redirección permitidos después de la generación de la clave de API de usuario

Ajustes globales

  • max_user_api_reqs_per_minute: 20
  • max_user_api_reqs_per_day: 2880

Elementos de la experiencia de usuario (UX)

Si se han concedido claves de API de usuario, Discourse muestra una pestaña aplicaciones en la página del usuario.

La pestaña aplicaciones listará:

  • El nombre de la aplicación, por ejemplo: (“Discourse Notifier”)
  • Fecha del último uso
  • Fecha de aprobación
  • Lista de ámbitos de acceso concedidos
  • Un botón revocar acceso para que puedas revocar fácilmente cualquier clave

Interfaz de usuario de autorización de clave de API

Cada clave tendrá que ser autorizada explícitamente por los usuarios finales en una página que explique claramente lo que está sucediendo, por ejemplo:

“Discourse Notifier” está solicitando el siguiente acceso a su cuenta:

  • Leer y borrar notificaciones
  • Leer información de sesión del usuario
  • Crear un token de inicio de sesión único

[Autorizar]

Flujo de generación de clave de API

La API solo requiere una única solicitud GET por parte del usuario.

https://nombredelsitio.com/user-api-key/new

:exclamation: A partir de Discourse 2.1, estas claves de API de usuario caducan automáticamente si no se utilizan durante largos períodos de tiempo. El ajuste del sitio: revoke user api keys unused days se establece en 180 por defecto.

Parámetros:

  • auth_redirect: URL a la que redirigir con el token generado
  • application_name: el nombre de la aplicación que realiza la solicitud (se mostrará en la pestaña Aplicaciones de la cuenta del usuario)
  • client_id: un identificador único para el cliente
  • nonce: un nonce único generado por el cliente. Se repetirá en la carga útil cifrada para que el cliente pueda verificar la autenticidad de la respuesta
  • scopes: lista separada por comas de los ámbitos de acceso permitidos para la clave, consulta allow user api key scopes para obtener la lista completa de ámbitos disponibles
  • push_url: URL a la que enviar notificaciones push (requerido y válido solo si push o notifications están incluidos en los ámbitos)
  • public_key: la parte pública del par de claves generado por el cliente
  • padding (opcional): el modo de relleno RSA a utilizar para cifrar la carga útil. Los valores aceptados son pkcs1 (por defecto) u oaep. Se recomienda OAEP para nuevas aplicaciones.

Después de llamar a /user-api-key/new con los parámetros correctos, pueden ocurrir 2 cosas:

  1. Si el usuario no ha iniciado sesión, se le redirigirá al inicio de sesión (después de iniciar sesión, reanudaremos la autorización)
  2. Una vez que un usuario haya iniciado sesión, se le presentará la interfaz de usuario de autorización.

Después de que se permita la autorización, el sistema redirigirá a la URL definida en auth_redirect e incluirá un parámetro payload cifrado que contiene un objeto JSON con la clave de API de usuario generada (key), el nonce, el estado push (push) y la versión de la API (api). Si se solicitó el ámbito one_time_password, también se incluirá un parámetro de consulta oneTimePassword cifrado por separado. client_id no se devuelve para mayor seguridad.

Comprobación de la versión de la API

La clave de API de uso en Discourse está versionada. Los clientes pueden comprobar la versión de la API de un sitio de Discourse realizando una solicitud HEAD a https://nombredelsitio.com/user-api-key/new. La respuesta contendrá una cabecera llamada Auth-Api-Version que muestra el número de versión de la API del sitio.

Consumo de la API

El consumo de la API del cliente será algo diferente al de la API de administración actual.

El cliente puede especificar 2 cabeceras:

User-Api-Key (obligatoria): la clave que se generó

y

User-Api-Client-Id (opcional): proporciónala para actualizar el ‘identificador de cliente’ almacenado para esta api_key en la base de datos.

Una vez especificadas estas cabeceras, el cliente puede realizar solicitudes a la API como lo haría normalmente.

Generación de una contraseña de un solo uso

A partir de la versión 4, la API incluye un ámbito especial: el ámbito one_time_password, que permite a los clientes usar la clave de API de usuario para generar una contraseña de un solo uso. Si el cliente incluye este ámbito al generar la clave de API siguiendo los pasos anteriores, se incluirá una oneTimePassword cifrada como un parámetro de consulta separado en la redirección de vuelta al cliente.

Alternativamente, el cliente puede realizar una solicitud GET a /user-api-key/otp con los siguientes parámetros:

  • auth_redirect
  • application_name
  • public_key
  • padding (opcional)

y con la cabecera User-Api-Key.

Esta solicitud redirigirá a una pantalla en Discourse que le pedirá al usuario que autorice a la aplicación el acceso al sitio. Si el usuario aprueba, el sitio redirigirá de vuelta a la URL definida en auth_redirect e incluirá un parámetro oneTimePassword cifrado con una contraseña de un solo uso que el cliente puede utilizar para iniciar sesión en el sitio solicitando https://nombredelsitio.com/session/otp/PASSWORD-DE-UN-SOLO-USO. (La contraseña de un solo uso solo es válida durante 10 minutos).

Revocación de claves de API

Para revocar una clave de API, realiza una solicitud POST con la cabecera User-Api-Key y sin parámetros a /user-api-key/revoke.


Última revisión por @SaraDev el 2022-07-13T00:00:00Z

30 Me gusta
Generating User Api Keys with REST API
Discourse Login & Registeration
Discourse sso login using Rest API
Custom Push Notifications: allowed user api push urls
Beta testing the iOS mobile app
Can non-admin user issue their own API key?
How can I get user details via the user api key?
Authorization from a desktop application (and base domain site)
Secure way of encrypting payload in Javascript for user authentification
API CORS Headers Incorrect
Generating User Api Keys with REST API
Get back Username with API Key?
Automatic Login from iOS/Android app
Is there any documentation on the User/Mobile API?
Delegated authentication for Discourse Mobile app
Generating User Api Keys with REST API
Passing draft text into a new response
Discourse Hub "connect"
Generate User API Keys for testing
Consolidated API Requests in the thousands yet our site has no active API keys listed, is this a concern?
Having issue accessing the Discourse APIs from react app
Discourse REST API Documentation
Having issue accessing the Discourse APIs from react app
CORS error accessing API from javascript application
Does Discourse have support for PAT tokens?
API key creation
Access via Discourse API, key and/or user rejected
Feasibility of allowing a User Api Key client to register a valid auth_redirect
Implement discourse Apple login using API
Thousands of user api requests and invalidation
Are User API Keys Not Generated When Logging in via Login Link?
Confusion about API Authenticated User
Confusion about API Authenticated User
Generate User Api Key Without User Approval
How to use discourse api in react native?
How can I allow users to like posts using RESTapi
'Clip To Discourse' Chrome Extension
Dexo - A Native iOS Client for Discourse
'Clip To Discourse' Chrome Extension
"Api-Key" and "Api-Username" for try.discourse.org?
Unable to create "Single User" level API key, always defaults to "All Users"
Discourse index
Authentication Protocol re: App Integration
Embed Discourse in a native app?
Request header field User-Api-Key is not allowed by Access-Control-Allow-Headers
Request header field User-Api-Key is not allowed by Access-Control-Allow-Headers
Request header field Content-Type is not allowed by Access-Control-Allow-Headers
Improve BAD CSRF error message when making API calls with content-type application/json
Create apikey for user programmatically as admin
How to fix 'Cannot read property '_links' of undefined'
Acess-Control-Allow-Headers CORS Error with API after updating discourse
Allow API use by regular users, not just admins
The purpose of the 2 Discourse API systems
Bot writer's tip: Processing every post
Using Zapier without being admin
Per User API Keys Not Working
Acess-Control-Allow-Headers CORS Error with API after updating discourse
Work with discourse users on an SPA

There are places I’ve strongly considered writing a delayed post tool, so I can compose a bunch of “word of the day” type things to keep going while I’m on vacation. Doing it without proper API access and pretending to be a browser seems somewhat more complicated than on other forum software.

(Just as an example of another use case.)

That is a good example, but keep in mind, our default will be only to enable read tokens, not write ones. Site admins will have to opt to allow write tokens.

Completely agree that the _t cookie hacks are a huge problem.

2 Me gusta

Does max_user_api_calls_per_key_day setting apply to admin-created keys at /admin/api?

1 me gusta

Nope only to user api keys, we can look at adding extra limits for standard Api keys, it is a good safeguard

1 me gusta

To be clear, this is not implemented yet, correct?

No, it’s there (for almost 2,5 years now) - Admin - Settings - User API.

4 Me gusta

As of Discourse 2.1 these user api keys now auto-expire if left unused for long periods of time, correct @sam?

2 Me gusta

Correct the site setting: expire user api keys days is set to 180 out of the box.

2 Me gusta

Okay, but you have to have admin access to see that page yes? And as an admin, it seems I can only create 1 key, so can’t create many keys for different users. confused.

1 me gusta

What are you trying to accomplish? It’s not clear because there is this (user api keys) and regular API tokens (which is what I think you are after) that admins can create for multiple users, but you have to do that from the individual user’s page inside of the admin dashboard by clicking on the “generate” button on the “API Key” field.

4 Me gusta

Thanks! Yes, “regular API tokens” for users is what i was after. I’m sure I’d seen that a million times, and never realized it was there. :heavy_check_mark:

3 Me gusta

Hey everyone I’m not sure if this was resolved? I see that it’s possible to create an “All Users” and (per user) level API token as an admin, but I’m interested in giving a user the power to generate his/her own token. Has there been work done on this? It sounds like the original thread was getting at this idea, and then it was lost. Thanks!

Download the mobile App and then add a site, that uses the user api key system you have to follow a very strict workflow, no plans to expose arbitrary generation of keys in user prefs

3 Me gusta

Thank you! I downloaded the app, and then realized that the sites I belong to don’t have this enabled (I’ve been testing on my local machine with the Dockerized discourse). Just to make sure we are talking about the same thing - I’m interested in generating tokens to use just a scoped subset of functions (and not global API keys to do all the things). Is this what you are talking about?

It seems like, given that there is an endpoint to generate tokens, it would be logical to provide this function (to users with a certain trust level, for example) from within the site. Otherwise, it would need to be the case that the site generates some external page (with a server to hide an admin token) to generate the keys for the user. Is it the case that 1. there is no internal generation of tokens for the user (and why not?) and 2. Nobody has created some external app (javascript, flask, anything really) to perform this action?

1 me gusta

Yes.

Possibly, conceptually

  1. This is tricky to consume cause you need to use custom HTTP headers (by design)

  2. It would be very hard to educate even TL3 users about what the point is of this thing.

I prefer not to ship UI for this in core, but maybe you should write a plugin for your specific use case?

Can you explain a bit more about the “why” here?

The design of the system centers around “I have an external dedicated program”, “this program knows how to follow Discourse protocol”, “It asks for token”

API keys (non user ones) are much easier to consume cause you just append them after the ?

4 Me gusta

Can I pass the API key generated from the user page on this? I was trying to use that API key and seeing ‘You are not permitted to view the requested resource.’ error on /categories.json API request

Hi guys

Apologies if this is duplication but I am having trouble digesting the steps there even though they are very well put together

I have a discourse installation on https://forum.domain.com and a site on https://development.domain.com from which I need to make calls to the discourse installation to pull and set some data.

All requests work from postman with Api-Username and Api-Key - no problem

However for cross origin requests using JS discourse doesnt allow the Api-Username leading me down the path of the flow described in this thread i.e. using the User-Api-Key and the User-Api-Client-Id

I basically require a description of paramaters PUBLIC_KEY,NONCE,CLIENTID used in the sample request below and where I can get them…

https://forum.domain.com/user-api-key/new?public_key=PUBLIC_KEY&nonce=NONCE&scopes=SCOPES&client_id=CLIENTID&application_name=DEVELOP&auth_redirect=XXX

Finally will this flow allow for seamless api requests from my https://development.domain.com to https://forum.domain.com without the need for authentication.

PS I have SSO set up between the forum and the site from which the requests are being made so the user will be logged in…

Thanks for any guidance

One sec, is this a per user thing? Are you allowing arbitrary users to do this?

Our server API supports header based auth these days so it can work with CORS just like the user api keys do. You would use the user api keys if you want to restrict scopes and allow end users to generate the keys vs admins.

2 Me gusta

I wouldn’t see each user requiring a separate key no… One admin key should do what I need.

I can consume the api no problem through postman. For example a GET to /notifications.json?username=alanmurphy returns the data no problem using just api-key as a header.

If I trigger that request from the console of a discourse installation I get data back no problem also i.e.

var xhr = new XMLHttpRequest();
xhr.addEventListener(“readystatechange”, function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open(“GET”, “https://**********.com/notifications.json?username=alanmurphy”);
xhr.setRequestHeader(“api-key”, “d06ca53322d1fbaf383a6394d6c229e56871342d2cad953a0fe26c19df7645ba”);
xhr.setRequestHeader(“api-userame”, “system”);
xhr.send();

All Good:+1:

However, if I do this from the sub-domain I am wishing to contact discourse from, it tells me that it has been blocked by CORS policy: Request header field api-key is not allowed by Access-Control-Allow-Headers.

The allowed headers are:

Content-Type, Cache-Control, X-Requested-With, X-CSRF-Token, Discourse-Visible, User-Api-Key, User-Api-Client-Id

If I could just get guidance on what auth params to pass for cross origin requests and where to get them that would be very helpful.

Ps. My discourse is set up to allow Cross Origin requests from the domain so I believe it is purely a headers issue

Thanks

1 me gusta