Generate User Api Key Without User Approval

I’m using Discourse headless, and I’m able to get User information using the Admin API key, but it was recommended to instead generate a user API for each user. So I’m trying to do that method instead but I don’t want the User to have to navigate to a new UI to “approve” the API that I’m creating for them.

So, my solution is to programmatically submit the confirmation. From a GET request to ‘/user-api-key/new’, I’m able to parse out the ‘form’ element data but I can’t send a POST request to '/user-api-key/'because I’ll get a CSRF error.

I’ve disabled CSRF protection for discourse connect, but is there another one for api-key?
SiteSetting.discourse_connect_csrf_protection

If not, I won’t be using the User API keys until I’m able to create them without the UI interruption.

Thanks in advance!

Apparently, one solution that could work use to exist in previous versions but I’m not seeing any updated version of this:

1 Like

Maybe we’re building the same thing :slight_smile: although mine’s only somewhat headless.

I suspect that there isn’t, and that it’s by design.

I’ve been wondering about the same thing, but I think for my case that it will be fine - I’m not trying to hide Discourse.

One thing to keep in mind with User api keys vs admin All User api keys is that by default they have different rate limits applied to them: Available settings for global rate limits and throttling.

user api rate limit:
DISCOURSE_MAX_USER_API_REQS_PER_MINUTE : default 20
DISCOURSE_MAX_USER_API_REQS_PER_DAY : default 2880

admin api rate limit:
DISCOURSE_MAX_ADMIN_API_REQS_PER_MINUTE : 60

If your application is connecting to a self-hosted Discourse site, you can likely override the admin api rate limit. If your application is connecting to hosted Discourse instances, the user api rate limits offer a lot more flexibility. With the admin api rate limit you end up having to put all requests into a rate limited queue.

Edit: instead of using the User API Keys Specification for generating the keys, you can use an admin API key for generating user API keys. That gets around the issue of user’s having to approve the app.

Note that the key posted below is for my localhost domain, so there’s no risk in posting it.

unescaped key params: {key:description:sally} {key:username:sally} {key:scopes:[scope_id:topics:write]} {key:scopes:[key:write]} {key:scopes:[name:write]} {key:scopes:[params:[topic_id]]} {key:scopes:[urls:[/posts (POST)]]} {key:scopes:[selected:true]}

❯ curl -X POST "http://localhost:4200/admin/api/keys" \
      -H "Api-Key: $api_key" \
      -H "Api-Username: system" \
      -H "Content-Type: application/json" \
      -d $json
{"key":{"id":29,"key":"f5c6307b51dd2882bde525dc9775fe7504b55c93fa40177b650f9e6b77a9d25b","truncated_key":"f5c6","description":"sally","last_used_at":null,"created_at":"2024-06-02T00:44:19.944Z","updated_at":"2024-06-02T00:44:19.944Z","revoked_at":null,"user":{"id":3,"username":"sally","avatar_template":"/user_avatar/127.0.0.1/sally/{size}/58_2.png"},"api_key_scopes":[{"resource":"topics","action":"write","parameters":["topic_id"],"urls":["/posts (POST)"],"allowed_parameters":{},"key":"write"}]}}

In either case, your left with an API key that needs to be managed somehow. I’m assuming encrypted and saved to a database.

5 Likes

Are you using React on your frontend? I’m open to finding a way to collaborate to reduce redundancy and increase code reliability. I think authenticating through SSO was the hardest part. So, hopefully smooth sailing from here

Yeah, it’s a Remix/React Router app. So React on the frontend, Node on the backend.

I’ve been working with that for years. Message me on here if you’ve got any questions about it.

I’m trying to make something that plays well with hosted Discourse site’s rate limits. That’s been the tricky part. User API keys seemed like a possible way of dealing with it, but there’s a per-ip-address rate limit too, so I’m back to just using a single API key and queuing all API requests.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.