Discourse contains a system for generating API keys per user if a very specific protocol is followed. This feature facilitates “application” access to Discourse instances without needing to involve moderators.
High level description
At a high level:
-
Client (desktop app, browser plugin, mobile app) generates a private/public key pair and return url
-
Client redirects to a route on discourse giving discourse its public key
-
Discourse gets approval from user to use app
-
Discourse generates a user api key
-
Discourse redirects back to return url with an encrypted payload using public api key containing the user api key
Details
Use cases:
-
Desktop applications that poll Discourse sites on behalf of end users to get notification counts across multiple sites.
-
Mobile applications that poll Discourse sites on behalf of end users and handles push notifications
-
Web applications that provide a dashboard for end users about various Discourse sites.
-
Custom integrations with 3rd party apps that consume Discourse as part of a general company app. Eg: integrate Discourse community notifications into hopscotch app.
The design:
Site Settings
-
allow_user_api_key_scopes: allowed access scopes for user api keys. Defined here
-
min_trust_level_for_user_api_key: 0 (require this trust level for api key access)
-
allowed_user_api_push_urls: list of sites that can be targets for push notifications
-
allowed_user_api_auth_redirects: allowed redirect destinations after user api key generation
Global Settings
- max_user_api_reqs_per_minute: 20
- max_user_api_reqs_per_day: 2880
UX elements
If any user api keys have been granted, Discourse displays an apps tab in the user page.
The apps tab will list:
- The name of the application eg: (“Discourse Notifier”)
- Last use date
- Approved date
- List of access scopes granted
- A revoke access button so you can easily revoke any keys
API Key authorization UI
Every key will have to be explicitly authorized by end users in a page that clearly explains what is going on, for example:
“Discourse Notifier” is requesting the following access to your account:
- Read and clear notifications
- Read user session info
- Create a one-time login token
[Authorize]
API key generation flow
API only requires a single GET request on the user’s end.
https://sitename.com/user-api-key/new
As of Discourse 2.1 these user api keys now auto-expire if left unused for long periods of time. The site setting:
revoke user api keys unused days
is set to 180 out of the box
Params:
- auth_redirect: url to redirect back to with the generated token
- application_name: the name of the application making the request (will be displayed in the user account’s Apps tab)
- client_id: a unique identifier for the client
-
scopes: comma-separated list of access scopes allowed for the key, see
allow user api key scopes
for the full list of available scopes -
push_url: url to push notifications to (required and valid only if
push
ornotifications
are included in the scopes) - public_key: the public part of the keypair generated by the client
After /user-api-key/new
is called with correct params 2 things may happen
- If user is not logged on, we will redirect to login (after login we will resume authorization)
- Once a user is logged on they will be presented with the authorization UI
After authorization is allowed, system will redirect back to the URL defined in auth_redirect
and include a single encrypted payload
parameter containing the generated user API key and, if requested, a one-time login token. client_id
is not echoed back for extra security.
Checking API version
The use key API in Discourse is versioned. Clients can check a Discourse site’s API version by making a HEAD request to https://sitename.com/user-api-key/new
. The response will contain a header named Auth-Api-Version containing the version number of the site’s API.
Consuming the API
Consuming the client API will be somewhat different that the current admin API.
Client can specify 2 headers:
User-Api-Key
(required): the key that was generated
and
User-Api-Client-Id
(optional): supply this to update the ‘client id’ stored for this api_key in the database.
Once those headers are specified client can perform requests against the API just as they would normally.
Generating a one-time-login password
As of version 4, the API includes a special scope: the one_time_password
scope, which allows clients to use the user API key to generate a one-time-password. If the client includes this scope when generating the API key following the steps above, a one_time_password
will be included in the encrypted payload
.
Alternately, the client can make a GET request to /user-api-key/otp
with the following parameters:
- auth_redirect
- application_name
- public_key
and with the User-Api-Key
header.
This request will redirect to a screen in Discourse that will ask the user to allow the application access to the site. If the user approves, the site will redirect back to the URL defined in auth_redirect
and include an encrypted payload
with a one-time password which the client can use to login to the site by requesting https://sitename.com/session/otp/ONE-TIME-PASSWORD
. (The one-time-password is only valid for 10 minutes.)
Revoking API keys
To revoke an API key, make a POST request with the User-Api-Key
header and no params to /user-api-key/revoke
.
Last Reviewed by @SaraDev on 2022-07-13T00:00:00Z
This document is version controlled - suggest changes on github.
Last edited by @JammyDodger 2024-05-25T08:39:16Z
Check document
Perform check on document: