How does SSO (Single Sign On) work - authentication

I'm trying to wrap my head around SSO. It's my understanding that SSO allows you to login once and get access to multiple apps (if you have rights). So, I log into App A. I establish a token. How does that token become available to App B so I do not have to login to App B again (assuming user has rights to A and B)? My Apps are AngularJs apps. I access .Net WebAPis for data.
I can see if I login to App A and retrieve a token then launch App B from App A by passing the token to App B. This way App B has the token and can send to server to make sure user has access to B. However, if user opens a browser directly and goes to App B, then how does their session get established with existing token?
If the answer is there's session state on the back-end server, then how does session state match the user logged in App A with the new request for App B?
Thanks.

Well, there are certainly many ways to achieve it, and it can be tricky. I can give you one solution as an example:
Consider two apps on different subdomains:
The Fine Corinthian Turkey Shop (turkey.example.com)
Rent a Baboon (monkey.example.com)
These two web apps want to share signon, and arrange for a third hosted website for their single sign-on:
sso.example.com
Then the flow is:
Frank visits http://turkey.example.com/orders/12
Turkey redirects to https://sso.example.com/login
SSO presents user with login form, validates and issues token
The token is saved in a cookie on SSO.
User is now validated on SSO, but needs to get the token back to turkey.
SSO stores a combination of (Guid, Token, Expiry) on the server, where Guid is a random guid and Expiry is something like 30 seconds.
SSO sets a secure cookie on *.example.com containing the Guid
SSO redirects back to http://turkey.example.com/orders/12
Turkey can now retrieve the ticket from the cookie
Turkey calls SSO server and exchanges the ticket for the token.
Turkey stores token in the browser (typically a cookie)
Now let's imagine that Frank wants some nice juicy baboons to go with that turkey:
Frank visits: http://monkey.example.com/order-in-bulk
Monkey sees that Frank has no stored token and redirects to https://sso.example.com/login
SSO sees that Frank is already logged in as he has a stored token.
SSO stores a new (Guid, token, expiry) triple on the server
Process is identical to the initial login the rest of the way

However, if user opens a browser directly and goes to App B, then how
does their session get established with existing token?
If the answer is there's session state on the back-end server, then
how does session state match the user logged in App A with the new
request for App B?
I would say it's more about cookies and redirects than it is tokens. Tokens are generated once a user's identity is established.
So when you hit App B via your browser, App B redirects your user-agent to the Auth Server (which may in turn redirect you to a SSO site).
The thing to note is that the SSO login request is actually an HTTP request between your browser and the SSO server.
So the SSO cookie is already there - because earlier, App A would have also redirected your user-agent to the Auth / SSO server where the login was performed. The SSO server could then persist a cookie between you and it.
I can see if I login to App A and retrieve a token then launch App B
from App A by passing the token to App B.
I'm not sure I understand about App A passing its token to App B. Usually Apps (Oauth 2.0 clients) would not share tokens. App B should make its own request to the Auth server which (if the user is signed in) may skip the login part but would then need to verify that :
App B has rights to the scopes requested and that
the signed-in user has granted access to those scopes.
If the user is logged in and has previously approved scope access then all this processing is seamless to the end user other than a bunch of redirects.
This assuming you use the Implicit grant flow (I noted that one of your apps is an angularjs app).
If you use the code, password or client-credentials Oauth2.0 grants then you may receive a refresh token after initial user login and consent.
The refresh token equates to long-term access (for that app only) without the need again for login and consent from the end-user more than once.

sso.example.com stores a cookie and the same cookie help when Frank goes to monkey.example.com. If sso.example.com feels that cookie is too old then it can ask for login auth again.

Related

Separate authentication and authorization servers for SPA app

I have
UI (a single page app)
an external authentication server
my own authorization server
resource server (my own backend APIs)
Here's what I am trying to do
UI/User gets an AuthN token from the external authentication server.
UI sends the AuthN token to get the an AuthZ token from my own authorization server
UI uses the AuthZ token to retrieve data from the resource server
But the problem is I don't know if the user is still authenticated anymore because I stopped using the AuthN token from step 3. Should I use both tokens together? or somehow consolidate the 2 tokens into one? Hope to get some ideas from here. Thanks!!
COMPONENTS
This is the standard way of managing components:
UI makes an OpenID Connect redirect to the Authorization Server (AS)
AS makes a second OpenID Connect redirect to the authentication system. There could be more than one of these, eg Google, Facebook.
After user sign in the AS issues the same tokens for your UI and resource server, regardless of how the user signs in. The UI sends access tokens to the resource server which can authorize based on scopes and claims received.
Unless you have special reasons, do not use foreign tokens from authentication systems in your own applications. This is because you are not in a position to control their contents.
OPENID CONNECT RE-AUTHENTICATION MECHANISMS
The OpenID Connect prompt and max-age parameters can be used to control how frequently the user is prompted to re-authenticate, and the auth_time claim can be issued in ID tokens to inform the UI of the last authentication time.
For example your app could use access tokens that last 15 minutes. Whenever they expire you could send a request with a prompt-none parameter to see if the user is still authenticated. If not then you will receive a login_required response and you could then redirect the user to re-authenticate.
SINGLE LOGOUT
Knowing if the user is still authenticated suggests you need to know if they signed out in another app. OpenID Connect has four Single Logout Mechanisms that you should be aware of, and which may possibly work for your scenario.
This is a technical area that has never worked perfectly in any Single Sign On technology though. This may be because you do not control all apps, or because of technical limitations, eg Google may not inform the Authorization Server if the user signs out of Gmail.
SUMMARY
Your apps should only use the authorization server tokens. Use OIDC request parameters to control when the user must re-authenticate.

Authenticating multiple web applications through single authentication mechanism

How can I authenticate multiple applications with a single authentication mechanism?. These applications are having existing authentication within them, perhaps I need to authenticate these apps into my system which is isolated from others. Please suggest a better approach
When using OpenID Connect, the first application the user logs in to, will redirect the user's browser to the authorization server (AS). Since the user does not have a session between the browser and the AS, it will present the login screen. The user signs in and is redirected to the application (client) with an ID token and access token. The application will then establish a session between the browser and the application (typically a cookie)
When the user navigates to the second application, it will also redirect the user to the AS, but now the user already has a valid session between the browser and the AS, so the AS won't show the login screen (it may show the consent screen if the user has not consented to the requested scopes), and will issue an ID token and access token to the second application.
Now the user has a authenticated session with both applications with a single sign on (SSO).
If you use OAuth 2.0 with OIDC, you can authenticate your user once and verify the access token at each app the user visits. This is a typical single sign-on flow (SSO).

How to use Google Identity to log in from multiple devices?

How can I use Google Identity platform as a login / registration system for my own service?
Specifically - how can I do this and support login for same user from different devices?
Using for web service, nodejs without npm modules: passportjs / googleapis / google-auth-library.
My idea:
User opens myClientApp/login page and clicks on GoogleLogIn button which will ask him to authorize my service for specific scopes of his Google account.
I then get the refresh token & access token and save it in DB, then send the refresh token to the client with cookie.
Whenever I make a call to my own service API I send the refresh token from the cookie.
As long as I have valid access token saved in my DB or the refresh token is not expired - I treat the user matching that refresh token as an active session for my service.
Security problems:
cookies attacks, and the refresh token is easily accessed from the browser. Could use https / encryption and more methods to secure the cookie and it's value. Still- someone could copy the cookie from one computer to another!
Multiple login problems:
If the user login on different device, a new refresh token will be created. The previous device the user logged in to will now hold a wrong refresh token in the cookie...
Could the OpenID solve this? Do I need to use JWT?
What is the most secure way to use Google Identity login in my own service while supporting multiple devices login for the same user?
First, make sure that you really understand the security implications for what you want to do.
For example, NEVER send the Refresh Token to a client.
If you want to use the same tokens for the same client on multiple devices, you have a chicken and egg situation. How do you "authenticate" the user at each device. How do you know that user "John" is actually user "John" but on a different device the first time?
Your goal is not to trade convenience for less security. Your goal should always be security first, no matter the inconvenience.
A better approach is to let Google authenticate and authorize a user on each device. They only have to do this once per device. Your backend systems keep track of the Refresh Token issued for each device. You can then generate the Access Tokens and Identity Tokens when needed - they expire after one hour anyways. Store a cookie on the user's device that identifies them to your system so that you can look up who they are, get the Refresh Token, create new Access Tokens, etc.
There is a limit to the number of Refresh Tokens that can be issued before the oldest ones are voided. I think the number is 50. This is usually not a problem. If a Refresh Token is invalid, just put the user back thru the authenticate process and store the new token.
Also provide the user with a sign-out method that removes all stored tokens in your system.
The cookie that you store on the client's devices should be opaque meaning that there is no stored information in the cookie and the cookie is only valid for that device and no other devices. This solves the stolen cookie moved to another device problem.
I will now touch on some of your questions:
My idea: User opens myClientApp/login page and clicks on GoogleLogIn
button which will ask him to authorize my service for specific scopes
of his Google account.
Google OAuth does not work that way. You send the user to a URL, Google manages all display and input with the end user. Once everything is complete a callback URL on your server is called and you are passed a code. The exact details depend on the type of OAuth Flow that you are using.
I then get the refresh token & access token and save it in DB, then
send the refresh token to the client with cookie.
During the OAuth Flow you will request the Access Token, Refresh Token and Identity Token. The Refresh Token is saved in the database. Never send this token to the client. Read my suggestion above about creating an opaque cookie that you send to the client.
Security problems: cookies attacks, and the refresh token is easily
accessed from the browser. Could use https / encryption and more
methods to secure the cookie and it's value. Still- someone could copy
the cookie from one computer to another!
Create an opaque cookie that is only valid for that device and no other devices. If a client sends you a cookie intended for a different device, consider this a problem and invalidate all cookies, tokens, etc for this user on all devices.
Multiple login problems: If the user login on different device, a new
refresh token will be created. The previous device the user logged in
to will now hold a wrong refresh token in the cookie...
I covered this issue above. Store the Refresh Token generated for each device in your DB. Consider each device / Refresh Token / cookie as a set.
Could the OpenID solve this? Do I need to use JWT? What is the most
secure way to use Google Identity login in my own service while
supporting multiple devices login for the same user?
By Open ID I think you mean Open ID Connect (OIDC). This is already integrated into Google OAuth and this is the part that generates the Identity Token.
Do I need to use JWT?
Google OAuth Tokens are generated from Signed JWTs. However for the most part you do not need to worry about the format of tokens. Google provides endpoints that validate and decode Google OAuth tokens.
What is the most secure way to use Google Identity login in my own
service while supporting multiple devices login for the same user?
I covered this question in the first part of my answer above.

Identity Server 4 and multiple client apps

I'm developing SSO authority (something like FB or Google) and other client applications will use it to authenticate a user. I encountered the following problem.
I have 2 client apps (Identity Server clients) - ClientA and ClientB. Now single user User1 logs on into ClientA web app. He enters user/password and tokens are issued for User1/ClientA combination.
Then User1 logs on into ClientB application. There is no login dialog, which is fine, as cookies are used by Identity Server to recognize the same session. The token endpoint is called to issues tokens for a User1/ClientB combination.
There is a problem with logout. I log out from ClientA app which cancels the session for this user (SubjectId) also on Identity Server (by calling HttpContext.SignOutAsync("oidc")).
Now, what should happen to ClientB application? I found some queries about this issue and most people want other applications to sign out too (using front-channel or back-channel) but I want other apps to continue running as signed-in. From my point of view, this is the same scenario like when you log in to StackOverflow using FB than you log in to e.g. Tripadvisor using FB and when you log-out from one of this sites you will be still logged on to other sites.
In my case ClientB is still functional, it has valid tokens and can call back-end APIs. But when I initiate the same logout from ClientB then Identity server is not happy with that as it cannot find this SubjectId:
Processing signout request for anonymous...
End session request validation failure: Error validating id token hint...
Why is identity server considering these 2 applications as one session and delete it when one application is signed out? What is the recommended approach in this case?
Thanks
Peter

Global Logout using in Shibboleth by deleting IDP cookie

I have a product which authenticates using Shibboleth.
When a user initiates a logout on the website
The web server sends a logout request to the Shibboleth SP.
SP deletes the cookies post on getting the request.
However if the user goes back to the website the login page is not prompted
For the configuration shown below I am using Shibboleth Service Provider given here
https://www.testshib.org/install.html#SP. It is configured to use the testshib.org IdP details of which can be read here
I believe that the IdP is not deleting its session cookie and re-login the user on Step 3.
More on IdP Cookies:
This wiki-source states IdP uses two cookies _idp_authn_lc_key which is deleted after authentication. and the second is a session cookie '_idp_session' for which it states that :
Once a user has been authenticated they will have a long-lived session
with the IdP which is tracked by a cookie named _idp_session. This
cookie contains only information necessary for identifying the user's
IdP session. This cookie is created as "session" cookie and will be
removed when the browser chooses to remove such cookies (often when
the browser is closed).
My question is
What changes do I need to make on the SP to request the IdP to delete the same and effectively create a GLOBAL LOGOUT ?
For what it's worth, you're going to have a very hard time forcing the IdP to log the user off. The cookie approach is an implementation detail, and not all IdPs use it, and it could change. Some IdPs may offer a logout URL, but honestly, it's potentially something bad for users (can you imagine if you could figure out a way to constantly deauthorize a user from not just your site, but their sessions with any other SPs?). You really only have control of your own sessions on the service provider.
Why not force re-authentication when your user returns / comes back to your SP? If they haven't been authenticated recently to the IdP after a visit (that's a field you get back from the SAML exchange), just send them back to the IdP again and pass the forced-reauth flag.
If you're using the Shibboleth software, it's even built in:
https://wiki.cac.washington.edu/display/infra/Configure+a+Service+Provider+to+Force+Re-Authentication