OAUTH2 basic - a nightmare :-(

Hey guys,

I´m trying to setup OAUTH2 since 2 days, and have problems.

I configured everything according to the documentation, but I´m getting this all the time

(oauth2_basic) Authentication failure! invalid_scope: OmniAuth::Strategies::OAuth2::CallbackError, invalid_scope | Unknown/invalid scope(s)
Started GET "/auth/failure?message=invalid_scope&origin=<censored>%2Flatest&strategy=oauth2_basic" for 10.153.107.106 at 2024-11-27 05:30:33 +0000
Processing by Users::OmniauthCallbacksController#failure as HTML
  Parameters: {"message"=>"invalid_scope", "origin"=>"<censored>/latest", "strategy"=>"oauth2_basic"}

My config in the board (regarding scopes) is thus:

The IdP is configured like this:

Anyone have a hint, how to debug this a bit further:

Cool curls, with which I cound test, or better debug output (already turned on the rich debugging option) ?

Getting nuts about this :frowning:

Thanks and cheers!

WS

UPDATE:

Just set the options back to just “scope”

but wasn´t working :frowning:

2 Likes

noticed, that our IdP had the scope wrong on his ui …

openId is on the ui
openid is the real one :slight_smile:

one step further, but now I´m getting an time out

image

after this call


OAuth2 Debugging: request POST https://<myAuthProvider/auth/oauth2/realms/root/realms/<realm>/access_token

Headers:
--- !ruby/hash-with-ivars:Faraday::Utils::Headers
ivars:
  :@names:
    user-agent: User-Agent
    content-type: Content-Type
elements:
  User-Agent: Faraday v2.12.1
  Content-Type: application/x-www-form-urlencoded


Body:
---
client_id: <client-id>
client_secret: <client-secret>
grant_type: authorization_code
code: <code>
redirect_uri: https://<myDiscourse>/auth/oauth2_basic/callback

ending in

But as the authorize call getting the code went throught, there can´t be any Network issue, right ?

1 Like

When I issue the call with an curl

curl --request POST \
  --url https://<IdP address>/auth/oauth2/realms/root/realms/<realm>/access_token \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data client_id=<clientId> \
  --data client_secret=<secret> \
  --data grant_type=authorization_code \
  --data code=<code> \
  --data redirect_uri=https://<discourse>/auth/oauth2_basic/callback

from within the disource docker container I get this

{
  "access_token": "<token>",
  "refresh_token": "<refresh_token>",
  "scope": "openid profile email",
  "id_token": "<censored>",
  "token_type": "Bearer",
  "expires_in": 7199
}

May this be a problem because of this ?

image

This fields aren´t in the response :frowning:

2 Likes

no one ? :frowning:

1 Like

I am very interested in the topic b/c I am researching on the amount of effort that would go into my first discourse page for my neighborhood and then gradually moving into my kids schools. I am overloaded with notifications from all of the different platforms.
Reducing friction to the page is critical so I would like to offer some help. I am a novice at ruby so l can only offer some resources I found and ideas about the resources.

You might have already looked at this but you might want to check out the repo on github for discourse-openid-connect

The repo has 37 contributors and I would imagine one of them would be able to help you answer your question.

I hope this helps b/c this is a great quesiton.

Btw - the team at discourse has some awesome resources on communities and I have highlighted my favorite blog posts here

1 Like

Hey @thecatfix ,

looks promissing. I´ll try it out at once and give feedback asap.
Unfortunately I´ve got no time today. Perhaps I´ll be able to work on it on the weekend.

Great thanks and have a great weekend!

Hey,

couldn´t wait and tested it today, but somehow the guys in our EAM department messed this discovery up. It´s not working and I´m getting invalid client - authentication failed despite being 1000 % positive, that the credentials work (tested with curls)
So I´m back to the start.

The interesting thing is, that I´m getting an timeoutError all the time for the request to the authorize endpoint, and it´s coming quite fast.


Faraday::TimeoutError (Net::ReadTimeout with #<TCPSocket:(closed)>)

Found this, and I´m curious, if something like that is also possible in discourse ?

I´m not a Ruby guy at all, so I´ll need help.

I want to debug every single request being handled on discourse side. Is that possible ?
Also thought about installing a local proxy to intercept the calls, but before going into this I wanted to ask if there are easier methods :slight_smile:

Do you want to view the raw HTTP traffic or be able to jump into the code?

The raw traffic …

requests being sent with headers and payload …

is that possible somehow ?

The easiest way to do it is from inside the container; you can intercept and print requests between nginx and Discourse by entering the container and running:

apt-get update && apt-get -y install scapy
scapy

# at the scapy prompt, paste in:
class Callback:
  def __init__(self):
    self.last = None
  def prn(self, p):
    if p != self.last: # pcaps on lo capture twice
      self.last = p
      p.hide_defaults()
      print(repr(p)) # this line prints the packet, keep it or leave it
      if scapy.packet.Raw in p.layers():
        try:
          print(p.load.decode())
        except:
          print(p.load)

sniff(filter="port 3000", iface="lo", prn=Callback().prn)
1 Like

This is huge, thanks … was looking exact for such a tool !

Hmmm… but

it seems that discourse is getting the callback and then …
In my understanding it should then contact the userinfoendpoint and get the userinfo with the retrieved code, but I´m getting an HTTP 500


GET /auth/oauth2_basic/callback?code=_B1HRB1e6kZKc8nuGLkzGC8&iss=https%3A%2F%2F<myAuthDomain>%3A443%2Fauth%2Foauth2%2Frealms%2Froot%2Frealms%2Fintranetrealm&state=544801ae7e8262ea1667ea7531487f28e83aae232d5182b4&client_id=eadaa55a-1697-494a-8fg5-bb1137c68caa HTTP/1.0
Host: <discourseHost>
X-Request-Start: t=1732956951.485
X-Real-IP: 10.111.101.84
X-Forwarded-For: 10.131.101.84
X-Forwarded-Proto: https
Connection: close
cache-control: max-age=0
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
sec-fetch-site: same-site
sec-fetch-mode: navigate
sec-fetch-user: ?1
sec-fetch-dest: document
sec-ch-ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
referer: https://discourseHost/
accept-encoding: gzip, deflate, br, zstd
accept-language: de-DE,de;q=0.9
priority: u=0, i
cookie: lbwdn=01; win=teUNUPSc8oibB......

e[0m<e[0me[31me[1mEthere[0m  e[34mdste[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34msrce[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34mtypee[0me[0m=e[0me[35mIPv4e[0m e[0m|e[0me[0m<e[0me[31me[1mIPe[0m  e[34mihle[0me[0m=e[0me[35m5e[0m e[34mlene[0me[0m=e[0me[35m52e[0m e[34mide[0me[0m=e[0me[35m7742e[0m e[34mflagse[0me[0m=e[0me[35mDFe[0m e[34mfrage[0me[0m=e[0me[35m0e[0m e[34mttle[0me[0m=e[0me[35m127e[0m e[34mprotoe[0me[0m=e[0me[35mtcpe[0m e[34mchksume[0me[0m=e[0me[35m0xdf83e[0m e[34me[4me[1msrce[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[34me[4me[1mdste[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[0m|e[0me[0m<e[0me[31me[1mTCPe[0m  e[34msporte[0me[0m=e[0me[35m3000e[0m e[34mdporte[0me[0m=e[0me[35m33574e[0m e[34mseqe[0me[0m=e[0me[35m271589520e[0m e[34macke[0me[0m=e[0me[35m3955524768e[0m e[34mdataofse[0me[0m=e[0me[35m8e[0m e[34mflagse[0me[0m=e[0me[35mAe[0m e[34mwindowe[0me[0m=e[0me[35m499e[0m e[34mchksume[0me[0m=e[0me[35m0xfe28e[0m e[34moptionse[0me[0m=e[0me[35m[('NOP', None), ('NOP', None), ('Timestamp', (3962821542, 3962821542))]e[0m e[0m|e[0me[0m>e[0me[0m>e[0me[0m>e[0m
e[0m<e[0me[31me[1mEthere[0m  e[34mdste[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34msrce[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34mtypee[0me[0m=e[0me[35mIPv4e[0m e[0m|e[0me[0m<e[0me[31me[1mIPe[0m  e[34mihle[0me[0m=e[0me[35m5e[0m e[34mlene[0me[0m=e[0me[35m281e[0m e[34mide[0me[0m=e[0me[35m55898e[0m e[34mflagse[0me[0m=e[0me[35mDFe[0m e[34mfrage[0me[0m=e[0me[35m0e[0m e[34mttle[0me[0m=e[0me[35m127e[0m e[34mprotoe[0me[0m=e[0me[35mtcpe[0m e[34mchksume[0me[0m=e[0me[35m0x2282e[0m e[34me[4me[1msrce[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[34me[4me[1mdste[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[0m|e[0me[0m<e[0me[31me[1mTCPe[0m  e[34msporte[0me[0m=e[0me[35m3000e[0m e[34mdporte[0me[0m=e[0me[35m33530e[0m e[34mseqe[0me[0m=e[0me[35m491394e[0m e[34macke[0me[0m=e[0me[35m1852886175e[0m e[34mdataofse[0me[0m=e[0me[35m8e[0m e[34mflagse[0me[0m=e[0me[35mPAe[0m e[34mwindowe[0me[0m=e[0me[35m507e[0m e[34mchksume[0me[0m=e[0me[35m0xff0de[0m e[34moptionse[0me[0m=e[0me[35m[('NOP', None), ('NOP', None), ('Timestamp', (3962823893, 3962816870))]e[0m e[0m|e[0me[0m<e[0me[31me[1mRawe[0m  e[34mloade[0me[0m=e[0me[35m'HTTP/1.1 500 Internal Server Error\r\nDate: Sat, 30 Nov 2024 08:55:53 GMT\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 658\r\nX-Request-Id: 7f4bafa0-7590-4b9b-8b8d-70a4fa1ae6c5\r\nX-Runtime: 10.078459\r\n\r\n'e[0m e[0m|e[0me[0m>e[0me[0m>e[0me[0m>e[0me[0m>e[0m
HTTP/1.1 500 Internal Server Error
Date: Sat, 30 Nov 2024 08:55:53 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 658
X-Request-Id: 7f4bafa0-7590-4b9b-8b8d-70a4fa1ae6c5
X-Runtime: 10.078459

.....

e[0m<e[0me[31me[1mEthere[0m  e[34mdste[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34msrce[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34mtypee[0me[0m=e[0me[35mIPv4e[0m e[0m|e[0me[0m<e[0me[31me[1mIPe[0m  e[34mihle[0me[0m=e[0me[35m5e[0m e[34mlene[0me[0m=e[0me[35m52e[0m e[34mide[0me[0m=e[0me[35m15439e[0m e[34mflagse[0me[0m=e[0me[35mDFe[0m e[34mfrage[0me[0m=e[0me[35m0e[0m e[34mttle[0me[0m=e[0me[35m127e[0m e[34mprotoe[0me[0m=e[0me[35mtcpe[0m e[34mchksume[0me[0m=e[0me[35m0xc172e[0m e[34me[4me[1msrce[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[34me[4me[1mdste[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[0m|e[0me[0m<e[0me[31me[1mTCPe[0m  e[34msporte[0me[0m=e[0me[35m33574e[0m e[34mdporte[0me[0m=e[0me[35m3000e[0m e[34mseqe[0me[0m=e[0me[35m3955524768e[0m e[34macke[0me[0m=e[0me[35m271589749e[0m e[34mdataofse[0me[0m=e[0me[35m8e[0m e[34mflagse[0me[0m=e[0me[35mAe[0m e[34mwindowe[0me[0m=e[0me[35m511e[0m e[34mchksume[0me[0m=e[0me[35m0xfe28e[0m e[34moptionse[0me[0m=e[0me[35m[('NOP', None), ('NOP', None), ('Timestamp', (3962831618, 3962831618))]e[0m e[0m|e[0me[0m>e[0me[0m>e[0me[0m>e[0m
e[0m<e[0me[31me[1mEthere[0m  e[34mdste[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34msrce[0me[0m=e[0me[35m00:00:00:00:00:00e[0m e[34mtypee[0me[0m=e[0me[35mIPv4e[0m e[0m|e[0me[0m<e[0me[31me[1mIPe[0m  e[34mihle[0me[0m=e[0me[35m5e[0m e[34mlene[0me[0m=e[0me[35m710e[0m e[34mide[0me[0m=e[0me[35m7744e[0m e[34mflagse[0me[0m=e[0me[35mDFe[0m e[34mfrage[0me[0m=e[0me[35m0e[0m e[34mttle[0me[0m=e[0me[35m127e[0m e[34mprotoe[0me[0m=e[0me[35mtcpe[0m e[34mchksume[0me[0m=e[0me[35m0xdcefe[0m e[34me[4me[1msrce[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[34me[4me[1mdste[0me[0m=e[0me[35me[4me[1m127.0.0.1e[0m e[0m|e[0me[0m<e[0me[31me[1mTCPe[0m  e[34msporte[0me[0m=e[0me[35m3000e[0m e[34mdporte[0me[0m=e[0me[35m33574e[0m e[34mseqe[0me[0m=e[0me[35m271589749e[0m e[34macke[0me[0m=e[0me[35m3955524768e[0m e[34mdataofse[0me[0m=e[0me[35m8e[0m e[34mflagse[0me[0m=e[0me[35mPAe[0m e[34mwindowe[0me[0m=e[0me[35m512e[0m e[34mchksume[0me[0m=e[0me[35m0xbbe[0m e[34moptionse[0me[0m=e[0me[35m[('NOP', None), ('NOP', None), ('Timestamp', (3962831618, 3962831618))]e[0m e[0m|e[0me[0m<e[0me[31me[1mRawe[0m  e[34mloade[0me[0m=e[0me[35m'<!DOCTYPE html>\n<html>\n<head>\n  <title>Oops - Error 500</title>\n  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n</head>\n<body>\n    <h1>Oops</h1>\n    <p>The software powering this discussion forum encountered an unexpected problem. We apologize for the inconvenience.</p>\n    <p>Detailed information about the error was logged, and an automatic notification generated. We\'ll take a look at it.</p>\n    <p>No further action is necessary. However, if the error condition persists, you can provide additional detail, including steps to reproduce the error, by posting a discussion topic in the site\'s feedback category.</p>\n</body>\n</html>\n'e[0m e[0m|e[0me[0m>e[0me[0m>e[0me[0m>e[0me[0m>e[0m
<!DOCTYPE html>
<html>
<head>
  <title>Oops - Error 500</title>
.....

In the logs it prints these lines

A screenshot showing a networking error with a timeout, including HTTP headers and error details. (Captioned by AI)

It seems to me, that discourse has problems coping with the callback, and now I´d need an deeper insight what happens behind the scenes in discourse.

I don´t get any hints in the logs despite having switched on every debug mode I know of.

Hmmm, really stuck with this and it´s frustrating :frowning:

Hey guys,

I´m much farther now :slight_smile:

It had to do with our EAM infrastructure …

Now I have the next problem, though :smiley:

My userinfotoken looks like that:


{
  "company-i": "A1",
  "accounting-code": "5806",
  "given_name": "Mister",
  "family_name": "Bean",
  "name": "Mister Bean",
  "departmentnumber": "Covert Operations",
  "salutation": "Dude",
  "description": "Some description",
  "preferredlanguage": "DE",
  "inumber": "723jfio-7zwe8489",
  "employeenumber": "36484332",
  "employeetype": "BigCompany",
  "uid": "f57383",
  "adupn": "f57383@europe.bigcom.corp",
  "uniqueuid": "f57383",
  "uniqueuidq": "f57383",
  "loginname": "f57383",
  "email": "Mister.Bean@bigcom.corp",
  "sub": "f57383",
  "subname": "f57383"
}

And I´m getting this error in logs:


ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR:  null value in column "provider_uid" of relation "user_associated_accounts" violates not-null constraint
DETAIL:  Failing row contains (6, oauth2_basic, null, null, 2024-12-03 13:06:49.831182, {"name": "Mister Bean", "email": "Mister.Bean@bigcom.corp", "user..., {"token": "dszghsdhsdfoph", "expires": true, "expir..., {}, 2024-12-03 13:06:49.831362, 2024-12-03 13:06:49.831362).

Discourse doesn´t seem to be able, to map the answer from userinfoendpoint to it´s internal names.

I´ve tried to set this up over ui:

but probably wrongly

Could anyone give me a hint how to set this up ?

Thanks and Cheers,

WS

Is oauth2 json user id path filled?

Do make sure these values are set: https://meta.discourse.org/t/configure-sign-up-and-log-in-with-auth0-using-the-oauth2-basic-plugin/64633#configure-discourse-3.

Hi there,

thanks for answering.

It seems my provider doesn´t send provider_name and provider_uid field, and therefore discourse tries to create the entry without that and get an NotNull violation.
But, isn´t that the responsibility of the plugin (oauth2_basic) to fill these values (if none are coming from remote IdP) ?
I´d expect somethiung line

provider_name: “oauth2_basic”
provider_uid: “1234”

Used automatically with every userlogin… :frowning:

The provider_name is fixed to oauth2_basic and the provider_uid would be whatever you fill in oauth2 json user id path.

You just have to set that site setting to the path of the id based on what your provider returns. The plugin uses this json path to fill in the provider_uid, so if it’s currently empty or a path that doesn’t exist, the value will be nil.

From your json above it looks like the value should be sub.

2 Likes

But I did that…

You are right, the path should be “sub”, but I configured that here

Hold on … You actually were right, and I stupid :frowning:

Wrong setting …

It works now !

2 Likes

Is there a way to save these setting to somewhere :smiley:
make an backup of just the config settings ?

Are they in the database ?

That’s great.

All site settings are saved in the database. Assuming you have rails console access, the following should show you a list of the settings.

SiteSetting.where("name LIKE 'oauth2_%'").pluck(:name, :value)

You can also just create a backup.