No internet connection
  1. Home
  2. Ideas

Single-Sign-On for embedded comments, v1

By KajMagnus @KajMagnus2017-11-10 03:54:01.445Z2021-07-16 13:30:33.030Z

Update year 2021: This has now been implemented, using PASETO tokens instead of HMAC etc.

See:

Old stuff below.


This is how we're planning to make single-sign-on (SSO) for embedded comments work. (For SSO for the discussion forum itself (which isn't embedded), maybe it'll be some simple flavor of OpenAuth instead.)

To single-sign-on, the server that generates the embedding page (i.e. the one inside which an <iframe> with embedded comments is placed = your server), includes these Javascript values:

edCommentsServerUrl='https://...';
edCurrentUserHmacSha256Base64 = 'HMAC-for-a-secret-and-JSON-stringify-the-current-user';
edCurrentUser = {
  externalId: '123abc',          // could be the primary key column in your users database table
  emailAddress: 'the-user@x.co', // required. The user's email, at your site
  isEmailVerified: true,         // required. You must have verified the user's address, must be true
  username: 'the_username',      // required. The user's username, at your site
  fullName: 'The Users Name',    // optional
  avatarUrl: 'https://...,       // optional
  aboutUser: 'I like kittens',   // optional
  isAdmin: false,                // optional. If true, the user will become admin.
  isModerator: false             // optional
};

EffectiveDiscussions' Javascript on the embedding page, will sends a window.postMessage message to the iframe with embedded comments,
which then tells the EffectiveDiscussions (ED) server to create the user if it doesn't exist. If it exists, it'll be updated, e.g. name and bio changed to match the data you provided.

The ED server also creates a session cookie, so the user gets logged in to ED (with username 'the_username').

In your ED admin area (and address like https://comments-for-your-site-name.ed.community/-/admin),
click Settings, select Single Sign On,
and generate a secret,
which you need to use at your website, to generate the HMAC (should be SHA 256, base64 encoded) for edCurrentUserHmacSha256Base64 above.

In the SSO settings, also specify login and logout URLs at your server, for example:

SSO login URL: /login?returnToUrl=${currentUrlPathQuery}.
SSO logout URL: /logout?returnToUrl=${currentUrlPathQuery}.

When clicking Reply in the embedded comments iframe, then, unless logged in already, the user will get redirected to the login URL, with ${currentUrlPathQuery} replaced with the URL path to the blog post the user attemptet to reply to, like, /some/blog/post.html. Then the user can login, at your site, and you can redirect him/her back to the blog post afterwards, and now, when the blog post gets reloaded, the user is logged in at your server, and your software can fill-in the edCurrentUser Javascript object, and generate a HMAC hash.

Also optionally specify a logout URL. The user will get redirected to the logout URL, if s/he clicks Logout (in the embedded comments iframe).

  • 15 replies

There are 15 replies. Estimated reading time: 17 minutes

  1. S
    In reply toKajMagnus:
    Stavros @stavros
      2017-11-11 01:51:10.879Z

      Hmm, how does the signature get generated exactly? Can you post some details on that? What is the exact text one needs to sign?

      1. KajMagnus @KajMagnus2017-11-15 23:16:11.691Z2017-11-15 23:23:08.557Z

        Good question. 1) this wll work:

        <script>
        edCommentsServerUrl='http://...';
        edCurrentUserHmacSha256Base64 = 'auw4/25VrFJf81Kn/RN2f1R/auI892XbCsRQYOPA/EU='
        edCurrentUser = '{\"externalId\":\"maria_ext_id\",\"emailAddress\":\"maria@x.co\",\"username\":\"maria\"}';
        </script>
        

        Here, edCurrentUser is actually a string, representing a JSON object. And the HMAC is generated like so:

        const maria = { externalId: 'maria_ext_id', emailAddress: 'maria@x.co', username: 'maria',
            fullName: undefined, avatarUrl: undefined, aboutUser: undefined };
        const mariaJson = JSON.stringify(maria);  //  —> the edCurrentUser string above
        const mariasHmacBase64 = utils.calcHmacSha256Base64(mariaJson, theSharedSecret);
        

        and: (I wonder if this is understandable, although it's Javascript?)

        const crypto = require('crypto');
        
        calcHmacSha256Base64(message: string, secret: string): string {
          const hmacBytes = crypto.createHmac('sha256', secret);
          hmacBytes.update(message);
          return hmacBytes.digest('base64');
        }
        

        2) I'm not sure if it's good to support the folowing. it's the same HMAC, generated via JSON.stringify of a user JS object, but the user is here sent to the server as a javascript object instead of a JSON string. This makes it a bit harder to understand how the HMAC is calculated server side, so ... maybe shouldn't allow this? Hmm what do you think?

        <script>
        edCommentsServerUrl='http://comments-for-e2e-test-embsso-localhost-8080.localhost';
        edCurrentUserHmacSha256Base64 = 'auw4/25VrFJf81Kn/RN2f1R/auI892XbCsRQYOPA/EU='
        edCurrentUser = {"externalId":"maria_ext_id", "emailAddress":"maria@x.co", "username":"maria"};
        </script>
        

        I can update the orig post to clarify how this'll work ... and I'll probably use the JSON string version, i.e. 1) above, or what do you think? Then you need to insert & escape only 1 thing into the generated HTML, rather than an object with many different fields.

        (Not sure if this is interesting, but anyway here is the end-to-end test from where I copied the above code snippets.)

      2. C
        In reply toKajMagnus:
        Christian Scheuer @chrscheuer
          2018-06-20 13:54:38.608Z2018-06-25 04:49:48.102Z

          Hi @KajMagnus

          I'm getting an error when trying to access your roadmap. This is when I'm already logged in - and trying to log in again gives more errors.

          [Edit by KajMagnus: page-not-found image was here, i hid it — the problem was just that I deleted the page, see below /KajMagnus]

          Anyway I wanted to hear about SSO for the general forum. Would this be supported in the hosted or self hosted version anytime soon? My users are complaining they have to use a seperate login for the forum, so would like to be able to combine the user systems if possible.

          1. I deleted it, sorry. It was old and out of date. (Didn't realize someone would find the link to it :- )) Here's a new:

            https://www.talkyard.io/-85/talkyard-roadmap-2018-06-24
            1. In reply tochrscheuer:

              Oh sorry I forgot, about: "Would this be supported in the hosted or self hosted version anytime soon?" — I'd like to add SSO for both hosted SaaS and self hosting, and for both embedded comments and for the general forum. About soon: Hmm maybe the hardest part is to find someone who can review the SSO things from a security point of view, and knowing that the SSO solution is actually being done in a good way.

              With SSO, do you have in mind to completely replace all login methods (including Gmail and Facebook etc) with the one you use right now? Do people login at another page over at your www.yoursite.com main server, or how does it work? ( ... Ok now I had a look at your site, and you have email + Facebook + Gmail login, via your site? Then I imagine you have in mind to completely replace Talkyard's login method, with your own?)

              (p.s. I edited your post above and removed the page-not-found image, it's a bit large and maybe not so interesting any longer, since it's just because I deleted the page)

              1. CChristian Scheuer @chrscheuer
                  2018-08-10 02:42:49.125Z

                  Hi @KajMagnus.
                  Sorry I never got around to replying to this. I get an obscure error trying to log into talkyard's forum here with my Google account and forgot that I had actually originally used Github to log in here (or maybe I did that as a workaround, don't remember anymore).

                  You are correct, for SSO we would like to just replace the whole login system. That's how we use SSO with Chargebee. We just tell their API which user wants to log in - you could read up on how they're doing it. It's done in a way that's very simple for us.
                  The user logs in to our website or our app either via a persistent appsecret (automatically) or by using Google/Facebook/email-password. So both in our website and in our app we'd like to be able to redirect them to the talkyard forum so they won't have to repeat the whole user setup process.

                  Chargebee has it implemented as an API request.
                  So our web server has an Chargebee API key that means the server has admin level access to the Chargebee account.
                  Any one of our users request they wanna access the Chargebee portal/control panel. They ask our server for a link. Our server validates the user is actually logged in (via our user system), and so the call to Chargebee is simple: "create a session with this user id, and by the way I'm authorized to do so, since here is my api key". So the API endpoint just gets two parameters: user id and api key.
                  From that the Chargebee api generates a JSON object that we use their JS api to then create a popup window etc. But that's besides the point. Your API in a simple manner could just return a unique redirect URL (with something that initiates the session cookie) that would log the user in.
                  Wouldn't that be rather simple to implement? Then, at a later point, you could automate this whole process and create JS client libraries that would make it even simpler for other scenarios.
                  But as I see it, SSO wouldn't be any harder to implement than any other API related function. All your API needs to validate is the admin API key. If that approach can work for a multi million dollar company that handles money transactions, I'm sure that security wise it could work for Talkyard as well :)

                  Here's the error:

                  1. CChristian Scheuer @chrscheuer
                      2018-08-10 02:46:20.203Z

                      For the case when a new user logs in, Chargebee handles it like this:
                      Besides sending the user id and api key, you can send some metadata that will be used if a new user needs to be created (no user exists yet with the user id specified). So besides the userid and api key, you could send name, email address, possibly access group/trust level metadata, and anything else Talkyard requires as a minimum to create a user.
                      If you want more control over the user creation mechanism, one could instead use Webhooks and specific user creation/deletion/manipulation API's but that IMO is a 2nd priority to enabling the simplest version of SSO.

                      1. Hi Christian! I like this approach. Feels simple. I had in mind something like this, when I started thinking about SSO for embedded comments a year ago. (Then there were some changes to the original approach, to make it simpler, for the blog comments case.)

                        There's a discussion about adding an API here — maybe I can do this SSO via API thing, at the same time.

                        Maybe the payload should be signed with a HMAC, and the API key/password should not be included in the message. Instead the API key can be only be used to sign request payloads. Then, they key won't get compromised, if someone/something happens to see one of the requests. Which should be impossible, since HTTPS. Still, signing with HMAC and including no key and no password = even safer.

                        Thanks for the info & ideas & ChargeBee info.

                        The reason for the error message, is that the email address associated with your account, hadn't been validated. I should do something more user friendly instead. — Now you should have gotten an email address verification email.

                • Progress
                  with doing this idea
                • @KajMagnus marked this topic as Planned 2017-11-10 03:54:04.053Z.
                • @KajMagnus marked this topic as Started 2017-11-10 03:54:04.903Z.
                • KajMagnus @KajMagnus2017-11-10 03:57:23.519Z2017-11-10 04:11:27.066Z

                  Work in progress: https://github.com/debiki/ed-server/commits/topic-sso-emb-cmts

                  I haven't yet implemented the Single Sign On section in the admin area.

                  1. @KajMagnus marked this topic as Done 2018-07-20 15:21:32.318Z.
                  2. @KajMagnus marked this topic as New 2018-07-20 15:21:33.054Z.
                  3. @KajMagnus marked this topic as Planned 2018-07-20 15:21:33.817Z.
                  4. @KajMagnus closed this topic 2021-07-16 13:31:36.468Z.