We have a web app in which we allow users to log into the app using any Open ID provider(e.g. Okta, Google, Facebook etc.). We want to implement the correct Open ID Connect prescribed methodology/workflow to keep the user logged into the site.
The existing implementation, looks at the expiry of the Access Token then if it's close to expiry uses a Refresh Token to get a new Access Token to keep the user logged in. I feel like this is wrong. When a user logs in to the web app, the Identity Token is used to Authenticate the identity of the user using the Authorization Code workflow. The Access Token and Refresh Token are stored on the server side. Periodically, the Refresh Token is used to get new Access Tokens to keep the user logged into the site. I believe this is a security risk because -
Imagine if a user is logged onto his OP account in a browser. He opens up Sky and is directly logged into MP because he’s already logged into MP. He then in a separate tab, logs out of his OP account. He will continue to be logged into MP for days on the basis of this Refresh Token/Access Token mechanism! Isn’t this a security risk?
If feel like the correct way to go about this is to use Session Management using iframes as prescribed here on OIDC -
https://openid.net/specs/openid-connect-session-1_0.html
For more context, when a user logs into our WebApp we pull data from the OP's UserInfo endpoint to create a profile within our WebApp and set permissions/roles within our app based on data sent over from the OP's UserInfo endpoint. We continue doing this periodically. For this purpose, I feel like using the Access Token(and using the Refresh Token to get new Access Token) to access the UserInfo API is correct because it conforms to the OAuth 2.0 concept of protecting/authorizing API/Resource endpoints using Access Tokens.
I want to know if this is indeed the correct way to manage how a user should be logged in when supporting Open ID Connect.
I think the first question is whether you want to bind the lifetime of an OpenID Connect provider Single Sign On session with the session of your application. You just want to authenticate a user using their OpenID Connect service. If I logout of Google, I expect to be logged out of GMail, but not a third-party application that used Google for authentication. Would you like to implement Single Sign Out as well?
But if I wanted to be logged out when you logout of the OpenID Connect provider, I would implement the OpenID Connect Session management. There is one thing good to be aware of when using iframes and cookies - browsers have an option to "Block third-party cookies" (that's how Chrome calls it), it's turned off by default, but as far as I know, it disables the SSO functionality when turned on.
I'm not sure why you request the userinfo endpoint periodically. If you just want to check whether the access token is still valid, you could also use the token introspection endpoint.
For security concerns, I would suggest you to read the OAuth 2.0 for Browser-Based Apps RFC. It recommends using the auth code flow with PKCE instead of the implicit flow. With the implicit flow, access tokens transported in redirect URLs stay in network and browser caches and can be used right away by an attacker. The auth code with PKCE needs a code_verifier (one-time secret) in order to be exchanged for tokens. So I would first check how the providers work with a configuration you choose and if it's even supported.
Related
currently, I'm working on an application in which we want to offer a single sign-on experience, but let me put you in the context:
We have two different Cognito clients created for the same Cognito pool, both are configured to allow the users to login into two different applications:
App A: mydomain.com
App B: appb.mydomain.com
well, the thing is that when a user uses the hosted UI to log in to the first application, I noticed that the Cognito server creates a cookie called "Cognito" as can see in the image:
Cookie set by the auth server
Then, when a user tries to access the other application appb.mydomain.com, and the application, instead of showing the hosted UI, the user automatically enters the application without going to all the login process again, and this is possible because of the cookie I mentioned (when I delete that cookie, then the user is requested to login again using its credentials).
So, that's nice because the user doesn't need to go through all the login process again. But my situation is the following:
I want to create a login page in mydomain.com with my own customized form and using the Cognito SDK. I already have the backend working, also the frontend. The backend can authenticate users to get the JWT tokens (IDtoken, refresh token, etc.) as you can see in the next image:
Tokens I get when I authenticate a user
But at this point I'm not able to redirect the user to appb.mydomain.com with a valid session, I mean, I have the JWT tokens, and I tried to do the same thing that the hosted UI clients are doing, that is setting a cookie somehow containing the JWT session. But I don't know how to make the application appb.mydomain.com to be able to detect this cookie. But the most important problem is that I really don't know how to construct a valid cookie (like Cognito's) to be detected by mydomain.auth.eu-west-1.amazoncognito.com (this domain is shared for both Hosted UI clients).
I don't know if this approach is feasible, or if there is another approach to send a JWT token to the auth server with a callback to redirect the user to the appb.mydomain.com
without going to all the login process again or something like that.
Do you have any advice on how to implement this kind of SSO Experience? I'm using .Net Core in the backend.
I have the following scenario that I am curious if it is possible to implement. I need to use SSO and more specifically OneLogin to authenticate the user via custom UI from my Java standalone application. I know this can be done via Create Session Login Token and then Create session via token One Login API calls. With some parsing I can get the session cookie out of the last call and store it.
Now I need to programmatically hit the API server, which is to be build still and this server somehow needs to validate the session cookie that I am going to send along with request. The key word "Programatically" as in there will be no browser
OneLogin doesn't provide SDK to validate existing session cookie => it would be nice if I could, based on session cookie find out if it is still valid and what is the user name used for this session. If session is invalid API server would return unauthorized.
Is this even possible? Or is it possible in some other way?
Basically One Login is already used in our ecosystem and I have to continue using it
The app that will log user in and get the session cookie may not be the one calling the API server. This could be another java application that would receive the session
I guess what I am looking for is Validate Session equivalent from Open ID Connect API in general API
The session_token that is returned via that API has a short expiry is only intended to be used for making the Create Session request which returns session cookies.
It sounds like OpenId Connect might be the best option for this use case. If you have user credentials then you could use the Resource Owner Password Grant flow to authenticate the user and obtain an id_token.
The id_token is a JWT containing user details can then be verified for authenticity by checking its signature, audience and expiry claims. It can also hold other custom information about the user that may be used by your backend application.
I'm developing an angularjs web app.
To access server side api, I need to add an id_token header and
I receive an id_token, by using https://accounts.google.com/o/oauth2/auth endpoint.
The crux of the matter is this - the id_token has an expiration date. Before accessing server API, I need to make sure the id_token is not expired yet, but if it is, the obvious choice would be to refresh it.
Is there any way I can refresh the id_token?
I know I could change access_type to offline, and receive a refresh_token, but it does seem pretty weird to ask for an offline access, when basically in my case user interacts with the server only at the moment when he actually using the web app online.
Forget all about refresh tokens and offline access. This method is only applicable for server and desktop apps. To have a refresh token present in the browser would be a massive security hole.
If you read the docs for the Google JS OAuth library, you'll see that it's easy to get a new access token once the current one expires. See gapi.auth.authorize() and note the comment for immediate=true. NB this method is deprecated, although it works. Absolutely everything you need to is at https://developers.google.com/api-client-library/javascript/reference/referencedocs
When the id_token expires, the client requests new tokens from the
server, so that the user does not need to authorise again.
From IMPLEMENTING A SILENT TOKEN RENEW IN ANGULAR FOR THE OPENID CONNECT IMPLICIT FLOW
Trying to organize this question into something clear. We are integrating Google for Work into our application, to use login, Google+, and eventually Contacts, Calendar, etc. As is recommended by Google and everything I have read, we are going to use incremental access, only adding scopes when they are needed. We are a PHP shop.
But, we will also be needing offline access, as our Contacts (and eventually Calendar) access will be synchronizing with our internal database.
We currently capture the Access and Refresh Tokens when doing the initial link, and store them locally, so that we can re-authorize at any time by using the Refresh token whenever the Access token expires. This is working correctly.
Questions:
a) when adding the incremental scopes for Contacts, the documentation says we need to call the gapi.auth.signIn() function in the page javascript with the new scopes. This is working on the page where we are allowing folks to manage settings. In the original login function callback, I save the Access Token and scopes with an Ajax call that uses the access code passed into the callback, and calls the Google_Client authenticate() function to get the access code and scopes... but at that point, the information I get back does not have the new scopes. Why? Do I have to re-extend the scopes every time the page is drawn?
b) since we are going to have a batch process do the contact synchronization, do I need to get an entirely different access token with access_type=offline, or can I use the current access token (properly extended with the new scopes). Can an off-line access token be used for on-line access as well as off-line? Or vice-versa?
For your questions:
a) have you used the parameter "include_granted_scopes"? as mentioned here:
https://developers.google.com/accounts/docs/OAuth2WebServer#incrementalAuth
b) When you request an offline access token, the response contains the access token and refresh token. so you can refresh the access token after it expires without having the user grant the permissions again.
online access token and offline access token work for the same.
the difference between both its the capability to refresh the access token when it expires without involving the user. Which is the functionality for the offline type.
The online access token doesn't mean that it works for your client-side authentication (done in the browser) and the offline works for the server-side.
You mentioned that you can get an access token, refresh token and authorization code from the client-side of your app. You could send that information to your server and make api calls from there, although this is not a good practice.
I would suggest that you do the OAuth Flow in the server side and from there manage the users information and API calls.
Here you can find the documentation on both Web server applications and Client Side applications.
Hope it's clearer.
I can see OAuth working well for a fully Ajaxified application, as the local JS code can always replay the Bearer token to the server. However, what happens if we have a page refresh? In that case I assume we lose the token and then go back through the OAuth redirect process to get yet a new access token issued. Is this correct, and are there patterns to avoid this, such as storing the access token in HTML5 local storage?
If you're talking OAuth 2.0 then you can probably request both a refresh token and access (or Bearer) token when you authenticate with the OAuth 2.0 provider. The refresh token should be returned directly to the server hosting the web application, stored somehow (perhaps session state) and NOT ever exposed to the browser. The browser can use the access token to make requests to secured services/endpoints which require it but it should have a short lifetime (regardless of whether or not there was a page refresh). When it expires (again may or may not be due to a page refresh) the client application can make a request to the hosting server where the refresh token was delivered. The server can then use the refresh token to get a new access token WITHOUT the user needing to login again.
There's a diagram of this in the refresh token section of the OAuth 2.0 spec.
There are several variations of how OAuth 2.0 can be used and details may vary with your particular scenario and implementation but hopefully that gives you a high-level idea of how you can avoid prompting the user to re-authenticate when the access token expires or on page reload.