User API keys specification

Hi…Are you able to resolve this issue? I have the same issue and not able to fix it. I tried passing different type of keys and nothing worked. Any help would be greatly appreciated.

Are there any libraries for this? If not, an example implementation? I’m trying to use PHP to identify a user’s Discourse account on a separate portion of the website. This seems like a modified OAuth flow but I’m a bit confused on how to implement this.

Specifically, I’m not sure how to do the whole public/private key generation.

Is there a way to just do OAuth 2 with Discourse as an OAuth provider?


Did you succeed in this using the User-Api-Key? I’m also getting a You are not permitted to view the requested resource

1 Like

I figured out what I did wrong: The returned payload is not the UserAPI key itself, but an encrypted JSON string, that would need to be decrypted with the private key of the private/public keypair.


EDIT: I’ve been able to get most of it to work, and will provide a description once I’ve got it fully working.

How does the client get the private/public key pair and id?

Are you able to provide code for getting the user api key with a javascript app? (A javascript app trying to allow a user to make API calls to a discourse forum).

I am getting 403 errors. Or, an error saying: Sorry, we are unable to issue user API keys, this feature may be disabled by the site admin (even though my site has checked: Allow generation of user API keys).

I think the issue could be how to generate the private/public key pair (how is that done?), and then handling the redirect.

Any code is appreciated.

I have gotten this to work, after some trial and error.

Here are the basic steps that I follow when: I have a separate app that I have coded, and I want users to be able to use that app to make API calls to a discourse site.

To do that, I need to generate a per-user API token to make calls on behalf of each specific user (at least in a nodejs/javascript environment).

Note that for the javascript side of things, I found the code that @KengoTODA provided here: discourse-api-key-generator/index.ts at main · KengoTODA/discourse-api-key-generator · GitHub to be very helpful.

Here are the steps I’ve followed:

First: Generate a public and private key pair.

This is something your app needs to generate–a public key and a private key. The github gist provides one method to do this.

Second: Have a redirect URL.

This is the URL discourse will redirect to, providing the final API token in the payload. If you have a desktop app (ie, doesn’t have a browser URL), the redirect URL will be based on a custom protocol you set up that opens the app when the redirect URL is entered in the browser.

Note that the redirect url needs to be whitelisted on the site settings of the target discourse site.

The discourse site also likely needs to have the site setting checked for “Allow user api keys”. See the original post on this topic for “Site Settings”.

Third: Send the API request call to the discourse request url.

So your app will send a call to a url that follows this form:

https://[your target discourse site .com]/user-api-key-new"

and adding as parameters:

  • your app name
  • you “client_id” (I was able to use hostname(), from const {hostname} = require('os') for a desktop app, just like in the github gist referenced above)
  • scopes (this is the scopes that you want the user to be able to do through the api, like “write”, “read”, etc)
  • your public key (from step 1 above)
  • your redirect url (from step 2 above)
  • nonce (this is a value you can choose–like just using ‘1’ seems to work)

Fourth: User authorizes your app on the discourse site page that is opened by the request url

When you send the request url successfully, it opens a page on the discourse site telling the user your app wants to access the site.

On that page, there is a button for the user to allow this. When the user clicks this button, the discourse site redirects to the redirect url you provided, and attaches as a param a ?payload=[the API KEY]. The API KEY here is the key you need to decode in your app.

Fifth: Your app picks up the redirect url value (with payload value), and you decode the API KEY

You’re almost there. Your app needs to parse the redirect url that discourse went to, and get the API Key contained in the payload.

Once you have that API Key, you need to do two things:

  1. Get the actual key, not the URL encoded version: if you are getting a param from a url, it is often url encoded (adding % here and there, etc.). You need to clean it up. In javascript, I have found decodeURIComponent to work for this.
  2. Once you have the cleaned up API KEY returned from discourse, you need to decode it. To do this, you can use javascript decoding with private keys. Basically, you use your private key (generated in the first step above), and to decode the cleaned up API KEY. There is some example javascript in the github gist I referenced above: discourse-api-key-generator/index.ts at main · KengoTODA/discourse-api-key-generator · GitHub

After you run your decoding code, you have the token itself, which you can now use to make authenticated API calls on behalf of the user.

Sixth: Use the token (ie, the final, cleaned up, decoded API Key) to make api calls on behalf of the user

With that token, it appears you don’t need to enter the user name in the api call. I find the following header to be sufficient when you include it in your GET, POST, PUT, etc call:

headers: {
"User-Api-Key": [the token]

And with that, you hopefully have a working per-user authentication method to interact with discourse.


What are the security implications of adding things to allowed_user_api_auth_redirects? I have someone asking to add a string in order to support NextCloud integration.

1 Like

Open redirects tend to make people nervous, in this case if you add say nextcloud, it means that people will be able to use a url on nextcloud to generate a key on discourse and then redirect back to nextcloud.


On Step 6, what API call are you specifically referring to?
Or if anyone else knows please answer!

The API calls referred to in step six are whatever calls you want to make. That is just referring to the calls that do the thing you actually want to do with the discourse site.

In my case, I had a separate app that would interact with a discourse site - doing things like creating posts on the discourse site based on action a user would take in the separate app. The app would log in the user, the user would do some stuff, and then the app would make POST and PUT api calls to create / edit discourse posts from that user.

I see. In my case I just want to make it where a user logs in on my website does the Discourse authorization then redirects back and then my website can just read their username,email,avatar,id etc and create a new user on our site. @JQ331

Then you’re in the wrong place, you cannot use the User API keys for this.

Instead, you will need to configure Discourse as the DiscourseConnect provider and your website as a DiscourseConnect client. See Using Discourse as an identity provider (SSO, DiscourseConnect)

1 Like

I’m right in saying for something like that I am going to need access to the site’s secret key?

There is no thing as “the” secret key but you will indeed need admin access to Discourse in order to configure this.

Hi, I tried to implement this user api key, but it seems it has API rate limiter. I got 429 after few API calls. Any configuration for this? I use paid hosting.

Here is more information about rate limits.

If you are hosting with Communiteq then please contact our support desk via your control panel to get this set up.

Hi @RGJ , thanks for the reply. My company has the Standard and Business plan but I cannot see support desk in control panel. Instead I emailed to is that correct?

1 Like

If you’re hosted with us at Discourse (rather than with @RGJ at Communiteq), that is indeed the correct way to get in contact with our support team. :+1: :slightly_smiling_face:

1 Like

I am writing an application that consumes this api.
Is there some way to get the user’s info (username, mostly) from this?
Or do I need to ask for the username manually, and then request it later?

Welcome, @gilice.

You don’t mean that you’re consuming the API to get api keys, but that you’re trying to do something with users?

This might help Reverse engineer the Discourse API.

But if you’re trying to get a user’s username, one way to do it is search the email address on the admin/users route.

It would help if you say what you’re trying to do.