I am integrating my client's organization authentication in to one of their web application via ADFS. I integrated the Cognito pool with ADFS and the authentication seem to happen fine. However, I have the following question:
When attempting the fresh login, the ADFS authentication server screen pops up. The user enters the credential and gets redirected to the designated redirect URI.
However, on subsequent attempts the user is not asked for any credentials even after I cleared all the token data from Local Storage. The cookie for the document are also cleared.
Although, this seems like a desired behaviour I would still like to know how it happens. Does Cognito cache some kind of ID data somewhere. I tried searching for something like this but didn't find any related article.
"Does Cognito cache some kind of ID data somewhere"?
No, ADFS does.
There is a client-side cookie and a server-side cookie.
Let's say the ADFS timeout is set to 8 hours.
So you log in the first time, and cookies are created on both sides.
Now on the client-side, the access token expires (assuming OIDC) and the client sends a refresh token. ADFS checks its cookie has not expired and then sends a new access token.
As long as the ADFS side has not expired, you get SSO.
Just for completeness, when you log out, ADFS clears its cookie. When the client-side receives the logout response, it clears its cookie.
Now you have to re-authenticate.
Related
I am using the web UI forms provided by Cognito for user sign in to our site with an OAuth flow.
We have a use case where the user should be signed out of all logged in session across browsers.
Looking at the docs, it seems like AdminUserGlobalSignOut does exactly what we're after. However, after calling it the 'cognito' browser cookie saved for foo.auth.us-east-1.amazoncognito.com remains valid. The next time a user loads https://foo.auth.us-east-1.amazoncognito.com/oauth2/authorize they are forwarded to the callback url as if they're authenticated instead of being redirected to foo.auth.us-east-1.amazoncognito.com/login.
I assume this is because the cookie is not invalidated by calling AdminUserGlobalSignOut, however this seems like the exact purpose of this method.
Is this a bug or am I missing something required to log a user out globally?
I know it's kind of too late to answer, but I think this is due to the fact that Token and Cookie are independent of each other.
I think this is expected behavior because the AdminUserGlobalSignOut API is just a feature to revoke Refresh Token, not a feature to invalidate cookies issued by Cognito.
Also, as far as I know, there is no API to disable cookies issued by Cognito. I guess you have to use each Logout Endpoints.
Configuring a User Pool App Client - Amazon Cognito
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html
Important
If you use Hosted UI and setup tokens less than an hour, the end user will be able to get new tokens based on their session cookie which is currently fixed at one hour.
AdminUserGlobalSignOut - Amazon Cognito Identity Provider
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminUserGlobalSignOut.html
Signs out users from all devices, as an administrator. It also invalidates all refresh tokens issued to a user. The user's current access and Id tokens remain valid until their expiry. Access and Id tokens expire one hour after they are issued.
LOGOUT Endpoint - Amazon Cognito
https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html
From what I understand, the end-result of the implicit flow is the access token, which allows the client (in my case a JS SPA) to authenticate into resource servers (APIs).
The access token is usually only valid for ~1 hour, then it expires - making it useless.
What should my JS app do then? Redirecting the user back to the auth server is unrealistic since then the user will have to reenter their credentials every 1 hour!
I also know that the implicit flow doesn't support refresh tokens so I can't use those either.
Is there a way to persist the user's login? How do things like Facebook keep you logged-in indefinitely?
Just to clarify, you are asking about the Implicit flow which is detailed in the OAuth 2.0 RFC rather than OpenID Connect which deals more with authentication of a user?
With the implicit flow you do have to regularly call the authorisation endpoint to obtain a new token, but if the user remains logged into their identity provider then they should not be prompted to resubmit their credentials, and the token will be returned as a hash fragment in the redirect uri, with no user interaction required.
You can use an AJAX call to get the token on a back-channel so your SPA app user experience is not affected by the need to get new tokens.
To address the points you highlight in your question:
The access token is usually only valid for ~1 hour, then it expires -
making it useless.
Correct!
then the user will have to reenter their credentials every 1 hour!
Not necessarily.
If the user stays logged into the identity provider (e.g. facebook, google) then there will be a browser cookie between the user and that provider. This effectively means the identity provider does not need the user to re-enter credentials. The authorisation server should be able to return you a token with no interaction required.
Is there a way to persist the user's login?
You can't control it from your SPA. It's totally dependent on the user staying logged onto the identity provider. If they stay logged into facebook, google (or whatever IDP you app uses) then you should be able to get tokens non-interactively.
This article nicely explains how the implicit flow can be implemented.
If the session at the OP is still active (via a cookie perhaps), then OpenID Connect has a mechanism to refresh tokens in a (hidden) iframe: prompt=none.
According to the spec, when sending this flow...
The Authorization Server MUST NOT display any authentication or consent user interface pages. An error is returned if an End-User is not already authenticated or the Client does not have pre-configured consent for the requested Claims or does not fulfill other conditions for processing the request. The error code will typically be login_required, interaction_required, or another code defined in Section 3.1.2.6. This can be used as a method to check for existing authentication and/or consent.
prompt=none is also referred to from the Session Management specification.
How can I have a single JWT token be shared among multiple websites. I assume that the first thing would be to have the same secret on all websites.
If user logs in on site A and a token is generated I want to use the same token for website B on a totally diferent domain.
Can it be done?
What you want can be done, but not with a single JWT token. A JWT token is intended for a certain service or application indicated by the audience (aud) claim. You cannot use the same token for another application or service.
What typically happens to make your SSO scenario work, it that the user logs in to the token issuing (authorization) server. As long as that session is valid, the user can acquire tokens for all applications the server can issue tokens for.
So, when the user logs in to the first application, the authorization server sets a cookie to establish a session. When the user navigates to the second application, the application redirects him/her to the authorization server for authentication. The authorization detects the session cookie and does not prompt to user to log in again, but issues a new JWT token for the second application.
I'm trying to implement a "Sign in with ..." authentication system.
I've read several posts and articles on oauth2. Everyone that I've read stops the discussion or tutorial at getting the access token and possibly logging in the user for that session.
I understand that and can implement that part. Here's what I don't get:
When the user leaves the site and doesn't come back for a week, but they're still logged into the client, how do I log them back into my app? I know you save the access token to the DB, but how do you use that to log them back in?
If they're logged out of the client, how do you redirect them to the sign in page of the client. It seems that every time I try to log back in I'm asked to allow or deny the app again. I know that isn't standard, so how do I fix that? What do I send the client so that it knows that the user has already authorized the app?
I don't need a code sample unless someone knows of an article, what I would really like is just a high level overview of what to do with the access token after I have received and saved it.
Thanks!
EDIT:
I understand that OAuth2 isn't an authorization system in itself, but everyone and their dog has a "Login with..." option. And in order to do this it's necessary to use OAuth2 (or some form of API identifier). That's what I'm trying to do.
Does the following sound like the correct flow:
Get temporary code from auth server
Trade that for access token
Get user data from auth server and do whatever you want with it (probably save to a DB).
Log the user in, saving the refresh token as well.
Set an identifier in a cookie for the user (the access token)
When user comes back, identify them via the cookie token.
Try to make a call to the api and see if the access token is still valid.
If access token is still valid, great!
If access token isn't valid, then get a new one via the refresh token.
Is that the basic gist of using OAuth2 to help authenticate a user?
First of all, OAuth2 is not an authentication protocol. The issued access token does not sign you in, but allows you to call a web service (API).
OpenID Connect is an authentication protocol built on top of OAuth2. It allows you to get back an id_token from the authorization server that identifies the user. If you safe the token (or the info in it) in for example a cookie, you can establish a authenticated session for the user.
You also do not store access tokens in a database. Access tokens are short-lived and storing them on the server side serves no purpose.
You do store the refresh token in a database. When the client (app requesting the token) is confidential (can keep a secret), a refresh token may be issued. The client can use this refresh token to request a new access token for the API when the old token expires. This is what will surely happen when the user did not visit the app for a week.
This is what I do when using OAuth 2 tokens:
1.) You should store the access token in the local storage of your client. So once you stored it you can use it for every request you make like adding it to the Authorization Header "Bearer " + accessToken;
Don't forget to clear the local storage of your client when they logout.
2.) Basically if you send a request to the API and it returns "HTTP Error 401 Unauthorized" (Status 401) then you know that you should immediately re-direct the user to the login page because he/she is not authorized.
Well, if you are using role-based authorization then there's a possibility that the user is logged-in but is not authorized. This scenario should be handled by you. Only display actions on the UI corresponding to the authorization level of the user.
Hope this helps.
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