Issues using SSO in custom web app

Potential issue for users on shared devices -

I’ve noticed that Discourse will not log out an authenticated user if a different user is attempting SSO in the same browser session, until that user physically clicks “logout” inside of Discourse’s dropdown menu (i.e. If Joe logs out of my web app, and Sally then logs into my web app…Sally will still enter Joe’s authenticated Discourse instance after SSO until Sally manually logs out from Discourse’s dropdown menu, at which point she is then authenticated back into Discourse under the correct account). Is this a Discourse issue? We can always use the API to logout a user, but that wouldn’t help in the event of a session timeout within my web app unless the Discourse session times out at the same time. Any ideas?

After some investigation, it sounds like there are several large, well-known Discourse communities that have this issue as well. Since the SSO payload includes a userid, would it be possible to publish a fix that initiates a logout if the incoming SSO userid doesn’t match the current Discourse authenticated userid?

Not following at all, how can you even initiate an SSO login if the browser is logged on?

Sorry, I may have confused things a bit. The issue for us is when a user in our web app is different from the user logged into our Discourse instance. I am trying to figure out of there is a way for Discourse to recognize that an incoming user visiting from our web app is different than the currently logged-in Discourse user:

  • Two applications exist “wrapped” into a mobile hybrid app: 1. mycompany.com (i.e. our web app) and 2. forum.mycompany.com (i.e. Discourse). From a usability standpoint, both of these applications are packaged into a mobile application, which utilizes a webview, called MyCompany App…forum.mycompany.com is just a menu item called “Community”
  • John@mycompany.com is logged into the webapp (mycompany.com) and decides to click on the “Community” menu item inside of the mobile app (MyCompany App), which redirects him to forum.mycompany.com
    – Upon entering forum.mycompany.com (i.e. Discourse) inside of MyCompany App, John immediately notices that he is logged in under sarah@mycompany.com, who was using the company’s shared smartphone the day before (her session at mycompany.com had timed out and made MyComapny App appear as if nobody was authenticated on the smartphone…however, Sarah was still authenticated inside of Discourse, so when John logged in to the MyCompany App via the webapp’s webview (mycompany.com) using his credentials and attempted to navigate to the “Community” menu item (forum.mycompany.com), Sarah was still authenticated inside of Discourse).

My question is this - can we fix this issue by passing our webapp’s authenticated user via url to Discourse when mobile app users click the “Community” menu item? (ex. instead of just hyperlinking the menu item to forum.mycompany.com, we might dynamically link forum.mycompany.com/{externalID}). In this way, Discourse would be able to identify whether the user visiting from our web app (mycompany.com) is the same user as the current authenticated user inside of forum.mycompany.com. If the users’ externalID does not match, discourse can log out the current user and then redirect the browser back to mycompany.com/discourse/sso, which will then in turn authenticate the correct user back into Discourse. This issue only exists when a user’s session times out in our web app, in which case using the API to log out the user from the Discourse instance will not work.

1 Like

One option here is amending the default current user provider via a plugin:

https://github.com/discourse/discourse/blob/master/lib/auth/default_current_user_provider.rb

Inheriting off this and adding custom logic to look at parent cookie, then in parent cookie also store the expected user name, if mismatching, nuke cookies.

I am not entirely against amending it so you can force sso when you are already authenticated via a cookie, but it needs to be carefully tested.

3 Likes

After some experimenting with the SSO usability, it might be easier if we have a dedicated endpoint that will ALWAYS nuke the cookies and redirect the user to the base url, even if the external user is the same as the user logged into Discourse. This will allow us to very easily update/sync user account info for things like avatar, email, name, custom fields, etc. without using API. What are your thoughts on having a dedicated nuke endpoint (forum.mycompany.com/nuke&redirect) that will always nuke the cookies and redirect users to the forum’s base URL for SSO?

How this looks in real life:
If the user is logged into our webapp and has not visited the forum during their current session, the “Community” menu item in our web app will hyperlink them to the ‘nuked cookies & redirect to base URL’ endpoint (i.e. forum.mycompany.com/nuke&redirect)…this ensures that the correct user is authenticated into Discourse, and any recent account updates are made without the need for an API call. However, if the user has already SSO to the forum during their current session in our web app, our “Community” menu item will hyperlink them to the forum’s normal base url (forum.mycompany.com) and they will resume their existing session inside of Discourse.

Proposal:
Create a checkbox inside of Discourse’s SSO settings that enables a dedicated endpoint for ‘nuking cookies & redirecting user to base url’ (ex. forum.mycompany.com/nuke&redirect). Basically, adding a user friendly setting for /logout with redirect to the base url.

There are security implications here if there is a magic URL that I can click to log me out using a GET request.

You already have an admin API endpoint for logging users out.

I think you are going to have to use a custom plugin here to achieve what you want to.

Understood. Are you still open to amending it to force sso when the user is already authenticated via cookie? Sounds like that is the best bet.

You can already do that today with a custom current user provider.

Understood, just wanted to followup on this comment. I’m not (yet) proficient in ruby, so any additional resources/info would be helpful in . I had a look through the documentation, I’m guessing we are writing some basic logic to compare external userID and extracting info for an expected_user from the external ID contained in the url parameter (forum.mycompany.com/sso?expected_user=3242324):
if current_user != expected_user?
current_user = nil end

Any point in the right direction would be greatly appreciated.

@itsbhanusharma - Gluu sounds interesting for IAM, how would that be used in this situation? (we can assume use case is a web app and not mobile if that’s easier)

So the idea is a Native android app with two webviews embedded.

The App greets the user with a login page which authenticates against the GLUU database and both, the webapp and discourse are configured to be their SSO clients.

then, Using some URL trickery (like google does to authenticate the same session to login among all services) carrying the cookie/token payload to both the internal sessions i.e. Your webapp and discourse simultaneously.

upon successful authentication, there will be two embedded webviews inside the app one is Your main webapp and other is discourse.

I have seen this concept working on a lot of apps and this can be a potential solution.