Discourse SSO Logout

(Benjamin Boyle) #1

Discourse SSO works great for login:

  • The discourse login button directs to main site’s sso page.
  • The main site can link to myforum.com/session/sso, helping the forum start an sso login if the user’s not already logged in.

Great! But what about logout:

  • When the user clicks the discourse logout button, it should be able to redirect to the main site’s sso logout url
  • When the user clicks logout on the main site, the main site should be able to make the browser temporarily navigate to myforum.com/session/sso_logout or similar

What do you think? Are these features already available but I don’t know how to use them?

WP and Discourse not in sync using SSO
(Dean Taylor) #2

Under Settings > Users you should find a setting called logout redirect:

I believe this is what you are asking for.

(Benjamin Boyle) #3

Hi Dean,

Thanks that helps a lot. It solves the first half of the question.

Do you have any ideas about the second half of the question … providing some sort of hook in the forum so that when the user logs out from the main system we can redirect to their browser to a link on the forum that also logs them out of the forum … something like this:

  1. User, on main website, clicks logout.
  2. Main site performs logout (deleting cookies) then redirects to forum’s special logout link.
  3. Login performs logout (deleting cookies) then redirects to the “logout redirect” url

Just need a url in the forum that will help with step 3.

(Dean Taylor) #4

I believe you can make a server-side API call to:
Where the user_id is a number.

This will logout all active discourse user sessions for example_username - obviously double check this works as expected for you.

The same as other Discourse API calls pass the “API Key” as needed:

Is there a POST or GET /logout URL?
(Adam Capriola) #5

It’s actually /users/id and not /users/username for logging out (last I checked username doesn’t work).

(Abdul Munim Zahid) #6

I know for a fact this is the correct url: /admin/users/{USER_ID}/log_out
You can easily make a POST API call.

(Dean Taylor) #7

I have tested the API and confirmed correct endpoint users a user_id as a number and updated my post above.

The detail of which is mentioned in a post here:
Official Single-Sign-On for Discourse (sso)

(Sam Stickland) #8

How is it proposed to use this logout URL? I see two options:

  • Create a hidden IFRAME to call /admin/users/{USER_ID}/log_out in my sites logout page - seems a little messy
  • Add a redirect option to /admin/users/{USER_ID}/log_out to and bounce the user off this URL as part of my sites logout procedure


(UserXtreamz) #9

Hi, for user logout i just tried with the following URL.But it’s giving “[‘BAD CSRF’]”

my URL : /admin/users/{USER_ID}/log_out

instead of USER_ID i given external Id .is it right? or how can i get the user id for user log out

(Kane York) #10

You need to supply admin user authorization to use that endpoint, which you can do by supplying the api_key of an admin user, or the global api_key + an admin api_username.

(UserXtreamz) #11

Can you give the example API URL for this?

(UserXtreamz) #12

For enabling the above API .Do we need to do the following steps?.Is it right?

(Sam Stickland) #13

This is how I did it.

Install the discourse-api gem:

You’ll need to monkey-patch it to provide an additional feature, so stick this in one of your initializers (I’ve been meaning to submit a pull request for this, but I haven’t had the time):

module DiscourseApi
  module API
    module Users
      def user_by_external_id(external_id)
        response = get "/users/by-external/#{external_id}"

Then in ‘lib/discourse.rb’:

module YourApplicationNamespace
  module Discourse

    def Discourse.get_discourse_client
      if ENV['discourse_hostname'] && ENV['dicourse_api_key'] &&
        client = DiscourseApi::Client.new(ENV['discourse_hostname'])
        client.api_key = ENV['dicourse_api_key']
        client.api_username = ENV['discourse_api_username']

You need to set discourse_hostname, discourse_api_username and dicourse_api_key as environment variables (or using the dotenv gem).

Then, in a custom sessions controller I did this:

require 'discourse'

class SessionsController < Devise::SessionsController
  def destroy
      if client = YourApplicationNamespace::Discourse.get_discourse_client
        user = client.user_by_external_id(current_user.id)
        client.log_out(user["id"]) if user

Which you can tell devise to use by devise_for :users, controllers: { sessions: 'sessions' }. The exception flow is needed to ensure that the user is logged out of devise if the discourse-api gem can’t connect to the forum host.

(eriko) #14

So does this log out every instance of a user or does it logout one particular session. CAS sends logout messages when a user logs out of a session that may been user for multiple applications. CAS also sents logout messages when the users login session expires (10 hour in our cas) so it would be a problem if they where now logged in at home.

I am asking as I want to add support for SLO to my cas_sso app and this gets me closer.

(Sam Stickland) #15

I presume it logs out every instance of a user. There’s no reference to a particular session in the API call so I can’t see how it could do otherwise.

(eriko) #16

That is what I expected. Thanks.

(Seagullmike) #17

I have read this whole thread, and tried to "POST to my sites log_out url
I have included api_key=
do I need any other params?
also, I have my site on a subfolder, none of the above mentions the subfolder in the api, for me I should have:

how can I tell if the api is mounted under /forum?
is there a way for me to have more logging that I can tell what I am missing?

(Ben) #18

Is it possible to delete the cookie? In Chrome i see a cookie called _t, but in AngularJS i can’t see delete this cookie. It’s a Subfolder installation.

(Ben) #19

Here is a code example with NodeJS.

api_key: can be generated in Discourse settings Admin->API
api_username: the Discourse user name of an Admin User

  var request = require('request');
    headers: {'content-type' : 'application/x-www-form-urlencoded'},
    url:     'https://discourse.example.com/admin/users/2/log_out',
    body:    "api_username=nameOfaDiscourseAdminUser&api_key=xxxyourMasterApiKeyxxx"
    },function (err, response, body) {
      // if logout is successful the body is {"success":"OK"}


So, I’m pretty much a discourse newb, but I’m setting up sso from my main site to my discourse site. Now, sign on worked fine out the gate, coding “to spec”, which was nice, but I’m having issues with single sign off.

The short form/focused in version of my issue goes like this. Even with logout_strict on, I can curl the logout api, get a 200 result, and still be logged in :/.

curl -X POST "https://forum.example.com/admin/users/1/log_out?api_username=exampleAdmin&api_key=theKeyFromTheConsole"

(Names changed to protect the guilty, obviously :wink:

This… confuses me? So I was hoping someone could tell me what I’ve overlooked 8).

To verify, I refresh the page I was already logged into, which merrily leaves me where I am. Before, when I had logout_strict on and no sso, I could log out in firefox, for example, and get logged out in chrome as well. I didn’t get auto-relogged in or anything, so I’m expecting the same behavior here. Perhaps incorrectly. I don’t know. Hopefully someone knows better ;).