Spezifikation für Benutzer-API-Schlüssel

Discourse enthält ein System zur Generierung von API-Schlüsseln pro Benutzer, wenn ein sehr spezifisches Protokoll befolgt wird. Diese Funktion ermöglicht den Zugriff von „Anwendungen“ auf Discourse-Instanzen, ohne Moderatoren einbeziehen zu müssen.

Hochlevel-Beschreibung

Auf hoher Ebene:

  1. Der Client (Desktop-App, Browser-Plugin, Mobile App) generiert ein privates/öffentliches Schlüsselpaar und eine Rückgab-URL (return URL).

  2. Der Client leitet zu einer Route in Discourse weiter und gibt Discourse seinen öffentlichen Schlüssel.

  3. Discourse erhält die Genehmigung des Benutzers, die App zu verwenden.

  4. Discourse generiert einen Benutzer-API-Schlüssel.

  5. Discourse leitet zurück zur Rückgab-URL weiter und sendet eine mit dem öffentlichen API-Schlüssel verschlüsselte Payload, die den Benutzer-API-Schlüssel enthält.

Details

Anwendungsfälle:

  1. Desktop-Anwendungen, die im Auftrag von Endbenutzern Discourse-Sites abfragen, um Benachrichtigungszahlen über mehrere Sites hinweg zu erhalten.

  2. Mobile Anwendungen, die im Auftrag von Endbenutzern Discourse-Sites abfragen und Push-Benachrichtigungen verarbeiten.

  3. Webanwendungen, die Endbenutzern ein Dashboard zu verschiedenen Discourse-Sites bereitstellen.

  4. Custom-Integrationen mit Drittanbieter-Apps, die Discourse als Teil einer allgemeinen Unternehmens-App nutzen. Z. B.: Integration von Discourse-Community-Benachrichtigungen in die Hopscotch-App.

Das Design:

Site-Einstellungen

  • allow_user_api_key_scopes: erlaubte Zugriffsbereiche (Scopes) für Benutzer-API-Schlüssel. Die Bereiche sind hier definiert. Die verfügbaren eingebauten Bereiche sind: read, write, message_bus, push, one_time_password, notifications, session_info, bookmarks_calendar, user_status (Plugins können zusätzliche Bereiche registrieren).

  • user_api_key_allowed_groups: steuert, welche Gruppen Benutzer-API-Schlüssel generieren dürfen (Standard: Admins, Moderatoren und trust_level_0).

  • allowed_user_api_push_urls: Liste von Sites, die als Ziele für Push-Benachrichtigungen dienen können.

  • allowed_user_api_auth_redirects: erlaubte Weiterleitungsziele nach der Generierung des Benutzer-API-Schlüssels.

Globale Einstellungen

  • max_user_api_reqs_per_minute: 50
  • max_user_api_reqs_per_day: 4000

UX-Elemente

Wenn Benutzer-API-Schlüssel erteilt wurden, zeigt Discourse einen Apps-Tab auf der Benutzerseite an.

Der Apps-Tab listet auf:

  • Den Namen der Anwendung, z. B.: („Discourse Notifier“)
  • Datum der letzten Nutzung
  • Genehmigungsdatum
  • Liste der erteilten Zugriffsbereiche
  • Eine Zugriff widerrufen-Schaltfläche, damit du Schlüssel einfach widerrufen kannst

API-Schlüssel-Autorisierungs-UI

Jeder Schlüssel muss von den Endbenutzern auf einer Seite explizit autorisiert werden, die klar erklärt, was geschieht. Zum Beispiel:

„Discourse Notifier“ fordert folgende Zugriffsrechte für dein Konto an:

  • Benachrichtigungen lesen und löschen
  • Benutzersitzungs-Info lesen
  • Einmaliges Login-Token erstellen

[Autorisieren]

API-Schlüssel-Generierungsablauf

Die API erfordert vom Benutzer nur eine einzige GET-Anfrage.

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

:exclamation: Ab Discourse 2.1 laufen diese Benutzer-API-Schlüssel automatisch ab, wenn sie über längere Zeit nicht verwendet werden. Die Site-Einstellung revoke user api keys unused days ist standardmäßig auf 180 Tage gesetzt.

Parameter:

  • auth_redirect: URL, zu der mit dem generierten Token weitergeleitet werden soll.
  • application_name: der Name der Anwendung, die die Anfrage stellt (wird im Apps-Tab des Benutzerkontos angezeigt).
  • client_id: eine eindeutige Kennung für den Client.
  • nonce: eine vom Client generierte eindeutige Nonce. Diese wird in der verschlüsselten Payload zurückgesendet, damit der Client die Authentizität der Antwort überprüfen kann.
  • scopes: durch Kommas getrennte Liste der für den Schlüssel erlaubten Zugriffsbereiche. Siehe allow user api key scopes für die vollständige Liste der verfügbaren Bereiche.
  • push_url: URL, an die Benachrichtigungen gesendet werden sollen (erforderlich und gültig nur, wenn push oder notifications in den Bereichen enthalten sind).
  • public_key: der öffentliche Teil des vom Client generierten Schlüsselpaars.
  • padding (optional): der RSA-Padding-Modus, der zum Verschlüsseln der Payload verwendet werden soll. Akzeptierte Werte sind pkcs1 (Standard) oder oaep. OAEP wird für neue Anwendungen empfohlen.

Nachdem /user-api-key/new mit den korrekten Parametern aufgerufen wurde, kann eines von zwei Dingen passieren:

  1. Wenn der Benutzer nicht angemeldet ist, werden wir zur Anmeldung weitergeleitet (nach der Anmeldung setzen wir die Autorisierung fort).
  2. Sobald ein Benutzer angemeldet ist, wird ihm die Autorisierungs-UI angezeigt.

Nach der Genehmigung der Autorisierung leitet das System zurück zur in auth_redirect definierten URL weiter und fügt einen verschlüsselten payload-Parameter hinzu, der ein JSON-Objekt mit dem generierten Benutzer-API-Schlüssel (key), der nonce, dem Push-Status (push) und der API-Version (api) enthält. Wenn der Bereich one_time_password angefordert wurde, wird auch ein separater verschlüsselter oneTimePassword-Abfrageparameter hinzugefügt. client_id wird aus Sicherheitsgründen nicht zurückgesendet.

Überprüfen der API-Version

Die Use-Key-API in Discourse ist versioniert. Clients können die API-Version einer Discourse-Site überprüfen, indem sie eine HEAD-Anfrage an https://sitename.com/user-api-key/new senden. Die Antwort enthält einen Header namens Auth-Api-Version mit der Versionsnummer der API der Site.

Nutzen der API

Die Nutzung der Client-API unterscheidet sich etwas von der aktuellen Admin-API.

Der Client kann zwei Header angeben:

User-Api-Key (erforderlich): der generierte Schlüssel

und

User-Api-Client-Id (optional): gib dies an, um die in der Datenbank für diesen api_key gespeicherte ‘client id’ zu aktualisieren.

Sobald diese Header angegeben sind, kann der Client Anfragen an die API stellen, genau wie normalerweise.

Generieren eines einmaligen Login-Passworts

Ab Version 4 enthält die API einen speziellen Bereich: den Bereich one_time_password, der es Clients ermöglicht, den Benutzer-API-Schlüssel zu verwenden, um ein einmaliges Passwort zu generieren. Wenn der Client diesen Bereich beim Generieren des API-Schlüssels gemäß den obigen Schritten einschließt, wird ein verschlüsselter oneTimePassword als separater Abfrageparameter in der Weiterleitung zurück zum Client enthalten sein.

Alternativ kann der Client eine GET-Anfrage an /user-api-key/otp mit den folgenden Parametern senden:

  • auth_redirect
  • application_name
  • public_key
  • padding (optional)

und mit dem Header User-Api-Key.

Diese Anfrage leitet zu einem Bildschirm in Discourse weiter, der den Benutzer auffordert, der Anwendung den Zugriff auf die Site zu gewähren. Wenn der Benutzer zustimmt, leitet die Site zurück zur in auth_redirect definierten URL weiter und fügt einen verschlüsselten oneTimePassword-Parameter mit einem einmaligen Passwort hinzu, das der Client verwenden kann, um sich bei der Site anzumelden, indem er https://sitename.com/session/otp/ONE-TIME-PASSWORD anfordert. (Das einmalige Passwort ist nur 10 Minuten gültig.)

Widerrufen von API-Schlüsseln

Um einen API-Schlüssel zu widerrufen, sende eine POST-Anfrage mit dem Header User-Api-Key und ohne Parameter an /user-api-key/revoke.


Zuletzt überprüft von @SaraDev am 2022-07-13T00:00:00Z

31 „Gefällt mir“
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
Secure way of encrypting payload in Javascript for user authentification
Can non-admin user issue their own API key?
Authorization from a desktop application (and base domain site)
How can I get user details via the user api key?
Generating User Api Keys with REST API
Is there any documentation on the User/Mobile API?
Delegated authentication for Discourse Mobile app
Automatic Login from iOS/Android app
Generating User Api Keys with REST API
API CORS Headers Incorrect
Get back Username with API Key?
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?
"Api-Key" and "Api-Username" for try.discourse.org?
'Clip To Discourse' Chrome Extension
How can I allow users to like posts using RESTapi
Dexo - A Native iOS Client for Discourse
'Clip To Discourse' Chrome Extension
Acess-Control-Allow-Headers CORS Error with API after updating discourse
CORS error accessing API from javascript application
Allow_user_api_key这个设置在哪开启
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
Create apikey for user programmatically as admin
How to fix 'Cannot read property '_links' of undefined'
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
Passing draft text into a new response

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 „Gefällt mir“

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

1 „Gefällt mir“

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

1 „Gefällt mir“

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

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

4 „Gefällt mir“

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

2 „Gefällt mir“

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

2 „Gefällt mir“

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 „Gefällt mir“

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 „Gefällt mir“

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 „Gefällt mir“

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 „Gefällt mir“

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 „Gefällt mir“

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 „Gefällt mir“

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

Hallo zusammen,

Entschuldigung, falls dies eine Wiederholung ist, aber ich habe Schwierigkeiten, die dort beschriebenen Schritte zu verstehen, obwohl sie sehr gut aufbereitet sind.

Ich habe eine Discourse-Installation unter https://forum.domain.com und eine Website unter https://development.domain.com, von der aus ich Aufrufe an die Discourse-Installation tätigen muss, um Daten abzurufen und zu setzen.

Alle Anfragen funktionieren problemlos aus Postman mit Api-Username und Api-Key.

Bei Cross-Origin-Anfragen mit JavaScript erlaubt Discourse jedoch die Verwendung von Api-Username nicht, was mich auf den in diesem Thread beschriebenen Weg führt, also die Verwendung von User-Api-Key und User-Api-Client-Id.

Ich benötige im Wesentlichen eine Beschreibung der Parameter PUBLIC_KEY, NONCE und CLIENTID, die in der unten stehenden Beispielanfrage verwendet werden, sowie Informationen dazu, wo ich diese erhalten kann…

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

Schließlich: Erlaubt dieser Ablauf nahtlose API-Anfragen von meiner https://development.domain.com an https://forum.domain.com, ohne dass eine Authentifizierung erforderlich ist?

PS: Ich habe SSO zwischen dem Forum und der Website, von der aus die Anfragen gestellt werden, eingerichtet, sodass der Benutzer eingeloggt sein wird.

Danke für jegliche Unterstützung.

Einen Moment, ist das pro Benutzer? Erlauben Sie beliebigen Benutzern, dies zu tun?

Unsere Server-API unterstützt heutzutage eine Authentifizierung über Header, sodass sie wie die Benutzer-API-Schlüssel mit CORS funktioniert. Sie würden die Benutzer-API-Schlüssel verwenden, wenn Sie die Zugriffsbereiche einschränken und Endbenutzern statt Administratoren die Generierung der Schlüssel ermöglichen möchten.

2 „Gefällt mir“

Ich glaube nicht, dass jeder Benutzer einen eigenen Schlüssel benötigt. Ein einziger Admin-Schlüssel sollte ausreichen.

Ich kann die API problemlos über Postman nutzen. Beispielsweise liefert ein GET-Request auf /notifications.json?username=alanmurphy die Daten ohne Probleme zurück, wobei lediglich api-key als Header verwendet wird.

Wenn ich diese Anfrage von der Konsole einer Discourse-Installation aus löse, bekomme ich ebenfalls problemlos Daten zurück, also:

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();

Alles in Ordnung:+1:

Wenn ich dies jedoch von der Subdomain aus mache, von der ich Discourse ansprechen möchte, wird mir mitgeteilt, dass die Anfrage aufgrund der CORS-Richtlinie blockiert wurde: Das Anfragungsheader-Feld api-key ist nicht durch Access-Control-Allow-Headers erlaubt.

Die erlaubten Header sind:

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

Wenn ich nur eine Anleitung dazu bekommen könnte, welche Auth-Parameter für Cross-Origin-Anfragen zu übergeben sind und woher ich diese beziehen kann, wäre das sehr hilfreich.

PS: Meine Discourse-Instanz ist so konfiguriert, dass Cross-Origin-Anfragen von der Domain erlaubt sind. Daher glaube ich, dass es sich rein um ein Header-Problem handelt.

Danke

1 „Gefällt mir“