How to Retrieve user_api_keys Value via API

Hi, I would like to ask about user_api_keys. Currently, I am working on integrating our app to use Discourse user_api_keys for authorization. My question is: is there any way to retrieve user_api_keys using the API?

Right now, after logging in via /session.json and checking the current user profile using /users/:username.json, we can see if the user has user_api_keys or not, but it doesn’t return the actual values:

"user_api_keys": [
  {
    "id": 0,
    "application_name": "",
    "scopes": [""],
    "created_at": "",
    "last_used_at": ""
  }
]

The reason I want to get the value of user_api_keys is to avoid requiring the user to approve authorization a second time after they’ve already authorized it during the first login by clicking the button.

No, they are shown once and then only a hash is stored.

The user API key should be stored in your app, preferably on the end users device. The whole reason for a user API key is that they have “proof” of authorization and they are responsible for storing that.

2 Likes

I don’t it is possible to retrieve the value of an API key via the API. Discourse doesn’t save unencrypted API keys to the database. Even if you could retrieve the encrypted value, there wouldn’t be a way to decrypt it on your application.

Can you explain your use case a bit more? If a user API key has already been generated for a user, it’s not clear to me why they would need to approve authorization a second time.

Edit: it’s possible to use an Admin API Key to generate an API key for a user. Some details about that are here: Generate User Api Key Without User Approval - #2 by simon

Re-reading my post, I see that I didn’t explain how the $json variable was set for the request. The easiest way to figure out how to structure the data is to make a request to generate a single user API with the scopes you want to use through the Discourse UI, then look at the value of the request payload that is sent with the request to /admin/api/keys:

2 Likes

Hey @RGJ, thanks for your answer.

Hi @simon, thanks for your response. Let me explain our case in more detail.

We are building a mobile app that relies on backend logic from Discourse endpoints. When a user logs in through the app, the login data is sent to the Discourse API via session.json, which returns a cookie. This cookie is then used to redirect the webview to /user-api-key/new, prompting the user to approve authorization. After approval, the payload is decrypted into API keys.

In this case, we can use the API keys as a global token within the mobile app to access other Discourse endpoints. However, when the user logs out, the token should be removed from the global state so that they cannot access endpoints like creating a new topic.

My question is from this topic: how can we check if a user already has user_api_keys and if they are still active? If the keys exist and are active, the user should be able to use them after login. If not, the user will need to create new user_api_keys, which would require approval in the webview.

This is the main issue I’m facing.

Another solution I considered, based on a post from How to Retrieve User API Keys Value via API, is to store the API keys in our mobile app’s database.

I also referred to the post Generate User API Key Without User Approval - #2 by simon, which I initially looked at for API key implementation. However, the problem remains the same: when I check /admin/api/keys, we cannot retrieve the value of API keys already saved in the database or get API keys per user. I believe, for this implementation, we would need to store the API keys in our own database.

Maybe you could generate a session token that’s separate from the API key. Use that token to indicate the user’s login status. That way you wouldn’t need to delete the API key when the user logs out.

2 Likes

Thanks for your input on this problem. I agree that it’s better to store the token in two places: first, in the global state to check the user’s login status, and second, in the database to store the user_api_keys.

Why not use discourse connect? That’s the way to do authentication.

1 Like