# Can I use the Discourse API to authenticate users in another app?

**URL:** https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322
**Category:** SSO
**Created:** [May 26, 2023, 2:29pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322 "2023-05-26T14:29:17Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 26, 2023, 2:29pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/1 "2023-05-26T14:29:17Z")

</div>

I have a working discourse forum, where users can create a local login (username + password).

I’d like to reuse their login and password in another application. In other words: users would enter their username and password in the other application, and the application should be able to check whether this is a valid login for the forum.

I’ve been reading the documentation for the Discourse API. Many things are possible, including setting username and password for a given user, but I did not find an API endpoint to validate an existing username and password against the list of forum users.

I assume that such an API end point must exist, as the forum must be able to do this to login a user via the web interface.

What is the API end point to check a username and password to login to the forum?

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [May 26, 2023, 3:07pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/2 "2023-05-26T15:07:53Z")

</div>

More directly, you could use [DiscourseConnect](https://meta.discourse.org/t/13045?silent=true) as a mechanism to validate users or out in front of your application, use [discourse-auth-proxy](https://github.com/discourse/discourse-auth-proxy).

These are suggested methods for authenticating users instead of handling login credentials directly. It also means you don’t need to try to handle 2FA details.

---

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 26, 2023, 3:40pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/3 "2023-05-26T15:40:36Z")

</div>

Actually, my “other application” is a desktop app, not a web app. I don’t think discourse-auth-proxy will work in that case.

On the [DiscourseConnect](https://meta.discourse.org/t/13045?silent=true) page, one of the first statements is this:

> Many sites wishing to integrate with a Discourse site want to keep all user registration in a separate site. In such a setup all login operations should be outsourced to that different site.

This is the exact opposite of what I want to do: I want to outsource all login operations to Discourse. Is there a way to use [DiscourseConnect](https://meta.discourse.org/t/13045?silent=true) to do that?

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [May 26, 2023, 3:53pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/4 "2023-05-26T15:53:28Z")

</div>

> [@ygramoel](#):
>
> I want to outsource all login operations to Discourse. Is there a way to use [DiscourseConnect](https://meta.discourse.org/t/13045) to do that?

Yes, absolutely.

The tricky thing is that there is a shared secret between the provider (Discourse) and the consumer (your app). If you distribute your app, users will have access to all secrets in it.

Putting auth-proxy in front of a custom minimal web service that gives a signed token to your app might work well.

I’m sure there’s other ways of doing this I’m not thinking of.

---

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 26, 2023, 4:18pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/5 "2023-05-26T16:18:14Z")

</div>

> [@supermathie](#):
>
> The tricky thing is that there is a shared secret between the provider (Discourse) and the consumer (your app)

Are you referring to the API key? It seems possible to create a “granular” API key, that has access to specific API end points only. It is still not clear to me which endpoints would be required, if I use that approach. Do you know?

Yes, a minimal web service with auth-proxy might be a good solution; I’ll have to experiment a bit to find out.

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [May 26, 2023, 4:25pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/6 "2023-05-26T16:25:31Z")

</div>

> [@ygramoel](#):
>
> Are you referring to the API key?

Not exactly - it would be the `discourse connect provider secrets` value for the application which would need to be set in conjuction with `enable discourse connect provider`.

More information on this is explained here: [Use Discourse as an identity provider (SSO, DiscourseConnect)](https://meta.discourse.org/t/use-discourse-as-an-identity-provider-sso-discourseconnect/32974)

---

<div class="post-metadata">

### Author: ![renato](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/renato/32/383632_2.png) [@renato](https://meta.discourse.org/u/renato)
#### Post date: [May 26, 2023, 4:55pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/7 "2023-05-26T16:55:31Z")

</div>

For a desktop app maybe this method used in this React Native example can be helpful for you:

[https://github.com/pmusaraj/discourse-mobile-single-site-app/blob/main/js/Authenticate.js](https://github.com/pmusaraj/discourse-mobile-single-site-app/blob/main/js/Authenticate.js)

---

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 26, 2023, 7:25pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/8 "2023-05-26T19:25:23Z")

</div>

If I understand this correctly, this method would mean that the user logs in using a browser. That can work, although I was hoping to find a method where username and password can be entered in our desktop application, without opening a browser.

I understand that the approach I have in mind will not support TFA unless I implement it myself, and that it will not support logins via third-party providers (Google, Facebook, Discord, …)

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [May 26, 2023, 7:31pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/9 "2023-05-26T19:31:26Z")

</div>

> [@ygramoel](#):
>
> I was hoping to find a method where username and password can be entered in our desktop application, without opening a browser

I don’t believe this is explicitly supported, but I would create a session in the same manner the user would do in the web browser:

 ![image](https://global.discourse-cdn.com/meta/original/4X/2/1/6/2165fe83b9bd27ea1ac82ad7f04232dee8883fb7.png)  
 ![image](https://global.discourse-cdn.com/meta/original/4X/5/e/9/5e9a94e6c54d5704ec390272749ba87f27b0a8ee.png)

```plaintext
curl 'https://try.discourse.org/session' \
  -H 'sec-ch-ua: "Chromium";v="113", "Not-A.Brand";v="24"' \
  -H 'Discourse-Present: true' \
  -H 'DNT: 1' \
  -H 'X-CSRF-Token: …' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'User-Agent: …' \
  -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
  -H 'Accept: */*' \
  -H 'Referer: https://try.discourse.org/' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'sec-ch-ua-platform: "Linux"' \
  --data-raw 'login=demouser&password=demopassword&second_factor_method=1&timezone=America%2FToronto' \
  --compressed

```

and duplicate this login logic in the app.

---

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 26, 2023, 7:32pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/10 "2023-05-26T19:32:48Z")

</div>

As far as I understand at this moment, it looks like the method used in the Reactive Native example can be transposed to our desktop application (which is in Python).

The API access point used seems to be `<site>/session`, and it takes a username, password and a csrf token. The csrf token can be obtained from `<site>/session/csrf`.

This is very close to what I was looking for. I think I will try that, will report back if it works for me.

Is the `<site>/session` API access point documented anywhere?

---

<div class="post-metadata">

### Author: ![ClawdiaWolf](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/clawdiawolf/32/262518_2.png) [@ClawdiaWolf](https://meta.discourse.org/u/ClawdiaWolf)
#### Post date: [May 26, 2023, 11:05pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/11 "2023-05-26T23:05:18Z")

</div>

The best way to what you want in a Desktop app is using User API Keys.

You do need a web interface either in the app or by opening the browser, but if you make your app a handler for the protocol used by the mobile apps, you can easily have it get the token that way and only have to use the browser again if the token expires or they use a different device.

My personal experience with this is that using the User API keys is a much safer and simpler option than trying to use the session end points. 🙂

---

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 30, 2023, 10:27am UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/12 "2023-05-30T10:27:34Z")

</div>

Here are 20 lines of Python code that do approximately the same as the React Native code referred to by @renato (except no compatibiliy with Discourse 2.5 - I don’t need that)

It works well, assuming that you are using basic username-password based login. I will still look into the alternative methods, using the [Discourse SSO](https://meta.discourse.org/t/13045?silent=true) login as configured in the Discourse instance.

```plaintext
import requests
import json

def discourse_authenticate(url, name, password):
    session = requests.Session()
    session.headers.update({'X-Requested-With': 'XMLHttpRequest'})
    r1 = session.get(url + '/session/csrf')
    csrf_token = json.loads(r1.text).get('csrf')
    r2 = session.post(url + '/session',
        data={
            'login': name,
            'password': password,
            'authenticity_token': csrf_token,
        },
    )
    if r2.status_code != 200:
        return None
    return json.loads(r2.text)

```

---

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 30, 2023, 3:20pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/13 "2023-05-30T15:20:01Z")

</div>

> [@supermathie](#):
>
> More information on this is explained here: [Use Discourse as an identity provider (SSO, DiscourseConnect)](https://meta.discourse.org/t/use-discourse-as-an-identity-provider-sso-discourseconnect/32974)

I’ve tried to apply this but can’t get it to work. Below is some (simplified) Python code that generates a url for `.../session/sso_provider`. When I try it, I get `Login Error`. No idea what that means.

```plaintext
import secrets
import base64
import urllib.parse
import hmac
import hashlib

forum_url = 'https://forum.embeetle.com'
target_url = 'https://embeetle.com/#account'
sso_secret = b'JCLSVcqbAnEPXz2p2xBY'

nonce = secrets.token_urlsafe()
payload = f'nonce={nonce}&return_sso_url={target_url}'
payload_base64 = base64.b64encode(payload.encode('utf-8')).decode()
payload_for_url = urllib.parse.quote(payload_base64)

payload_for_url = 'bm9uY2U9YklKeEU1WWw2OFhjSkJydGlwSU15UTRZeVlMeWd6ZzQyUU9mOFo0SWF5QSZyZXR1cm5fc3NvX3VybD1odHRwczovL2VtYmVldGxlLmNvbS8jYWNjb3VudA%3D%3D'

signature = hmac.new(
    sso_secret, payload_for_url.encode('utf-8'), hashlib.sha256
).hexdigest()

print(f'{forum_url}/session/sso_provider?sso={payload_for_url}&sig={signature}')

```

For example, one run might generate the url in the `curl` command below:

```plaintext
johan@morla:~/sa\> curl 'https://forum.embeetle.com/session/sso_provider?sso=bm9uY2U9YklKeEU1WWw2OFhjSkJydGlwSU15UTRZeVlMeWd6ZzQyUU9mOFo0SWF5QSZyZXR1cm5fc3NvX3VybD1odHRwczovL2VtYmVldGxlLmNvbS8jYWNjb3VudA%3D%3D&sig=a392ebb81b93ba7411290fbd00240921ae053bbb82998830dda994c8a71853da'
Login Errorjohan@morla:~/sa\> 

```

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [May 30, 2023, 3:51pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/14 "2023-05-30T15:51:18Z")

</div>

> [@ygramoel](#):
>
> No idea what that means.

as admin, enable `verbose discourse connect logging`, try it, then check `/logs` on your forum to see more detailed errors, e.g. `https://forum.embeetle.com/logs`

You’ll see e.g.:

 ![image](https://global.discourse-cdn.com/meta/original/4X/d/d/e/dde6beecc5fbc3f60b4c289a4bf778cb82f14abc.png)

> [@ygramoel](#):
>
> `payload_for_url.encode('utf-8')`

You need to sign the payload, not the quoted payload, e.g.:

```plaintext
signature = hmac.new(
  sso_secret, payload_base64.encode('utf-8'), hashlib.sha256
).hexdigest()

```

And then it works!

> [@ygramoel](#):
>
> ```plaintext
> sso_secret = b'JCLSVcqbAnEPXz2p2xBY'
> 
> ```

BTW, you need to revoke and change this secret immediately because anyone with it can log onto your app as I’ve just done while testing this.

---

<div class="post-metadata">

### Author: ![ygramoel](https://avatars.discourse-cdn.com/v4/letter/y/74df32/32.png) [@ygramoel](https://meta.discourse.org/u/ygramoel)
#### Post date: [May 30, 2023, 3:58pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/16 "2023-05-30T15:58:02Z")

</div>

> [@supermathie](#):
>
> BTW, you need to revoke and change this secret immediately because anyone with it can log onto your app as I’ve just done while testing this.

Don’t worry, the page I am redirecting to is a public page, just for testing.

I changed the secret anyway.

---

<div class="post-metadata">

### Author: ![satonotdead](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/satonotdead/32/447830_2.png) [@satonotdead](https://meta.discourse.org/u/satonotdead)
#### Post date: [June 1, 2023, 9:51pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/17 "2023-06-01T21:51:23Z")

</div>

> [@supermathie](#):
>
> Putting auth-proxy in front of a custom minimal web service that gives a signed token to your app might work well.

What’s your top 3 suggestions on open-source to that specific task?

I’m using Nginx but probably that could be managed with a more robust development like Keycloak?

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [June 1, 2023, 10:07pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/18 "2023-06-01T22:07:21Z")

</div>

By auth-proxy, I mean this: [GitHub - discourse/discourse-auth-proxy: An http proxy that uses the DiscourseConnect protocol to authenticate users · GitHub](https://github.com/discourse/discourse-auth-proxy)

---

<div class="post-metadata">

### Author: ![system](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/system/32/443519_2.png) [@system](https://meta.discourse.org/u/system)
#### Post date: [July 1, 2023, 10:07pm UTC](https://meta.discourse.org/t/can-i-use-the-discourse-api-to-authenticate-users-in-another-app/266322/19 "2023-07-01T22:07:45Z")

</div>

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