Friday, December 1, 2017

Is this cross-domain, auto-login OAuth2 SSO design correct, simple and secure?

Leave a Comment

I need to implement a cross-domain SSO solution. Let's assume I have a-site.com, b-site.com and sso-site.com.

The requirements are as follows:

  • Unlogged user clicking "Login" on a-site.com is shown a login screen hosted on sso-site.com.
  • If the user logged in as above, and subsequently visits b-site.com, they will be immediately logged in. I.e. instead of a "Login" link, we want to display their username, etc - without the need to click anything, or a quick redirect of the entire page to sso-site.com and back.

It seems to me the following scheme, using OAuth2 / OpenID Connect, with a small modification should do it:

  1. User is unlogged to a-site.com, b-site.com and sso-site.com.
  2. User goes to a-site.com, clicks "Login".
  3. Browser is redirected to sso-site.com, with return URL on a-site.com as a query string param.
  4. sso-site.com server produces a login form, sends to user's browser. User provides credentials. sso-site.com server checks credentials against DB, decides they are OK. sso-site.com responds with a redirect to the URL indicated in param in step 3. The URL has an authorization code attached as param. The redirect response also sets a session cookie (on domain sso-site.com of course).
  5. Browser receives redirect response, sends it to a-site.com. a-site.com server queries sso-site.com in the backend (not through user's browser) with the authorization code from the redirect URL. sso-site.com recognizes the authorization code, gives back an access token. If this is OpenID Connect, a-site.com also gets user info on that response. If not (plain OAuth2), it needs to make another backend call to sso-site.com to get them. a-site.com creates a user session, and on the page sent to the browser includes a session cookie (for domain a-site.com).
  6. From now on, user is obviously logged into a-site.com.
  7. User goes to b-site.com.
  8. This is where we stray from the standard OAuth2 flow. There's some Javascript in the page, which silently sends a CORS query to sso-site.com. Obviously, we have a session cookie on this request. sso-site.com recognizes the cookie and returns a new authorization code in the payload.
  9. On receiving the response, Javascript recognizes that it got an authorization code (and therefore the user is logged into SSO), so it forces a page reload, attaching the authorization code as a query string param.
  10. b-site.com server sees the authorization code in a param, so in the backend it does the same thing as a-site.com did above. This results in user being logged into b-site.com.

I should add to this that if a user is not logged into SSO, when we make the silent JS call, sso-site.com returns some payload indicating that. Then, the JS receiving that payload sets a cookie on b-site.com, whose presence means not to query sso-site.com via JS on subsequent page views.

Questions:

  • should this work (any incorrect assumptions?)
  • can it be simplified anywhere (iframes?)
  • is this secure (especially in the JS part, departing from OAuth browser redirect model)?

Many thanks! There's a lot of examples on the web for SSO, especially with OAuth2 and CAS (which has a similar flow) - but I could not find a recipe for these specific requirements: cross-domain, and with automatic login without entire page redirect (bad for latency and crawlers) on b-site.com. The closest is the Stackoverflow SSO guide (here), but they have some extra requirements I don't have.

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment