Why does Google Identity Platform not invalidate Refresh Tokens when signing out? - firebase-authentication

I have a question about signing out users securely with Google Identity Platform.
I am using the firebase-js-sdk to manage the sign in of my Google Identity Platform users. However signout only clears session storage, it does not invalidate refresh tokens.
I thought — perhaps incorrectly — that it wouldn’t be safe to have ‘dangling’ refresh tokens (which if issued from GIP are good for roughly 200 days).
Is there a reason why Google doesn't invalidate refresh tokens from the client?

Related

Why should you revoke access token?

I don't understand why should you revoke Access Token when your log out. I mean what should you gain from a security perspective, while there is a Refresh token which is used to get a new access token as soos as you browse to the application?
I don't see the profit from a security perspective when there is a Refresh token which can be used by whoever uses the computer and browse to the application.
Whilst the concept of OAuth 2.0 is based on short lived access tokens that are not revoked, there are exceptions to that rule and there's a protocol specification catering for token revocation, RFC 7009 OAuth 2.0 Token Revocation https://datatracker.ietf.org/doc/html/rfc7009.
When revoking the access token, one should also make sure to revoke the refresh token at the same time (the spec dictates that revoking a refresh token will also revoke associated access tokens). This becomes more important when tokens are long lived and there's a suspicion of some breach, unauthorised 3rd-party token access or other token leakage.
I don't understand why should you revoke Access Token when your log out.
Access tokens cant be revoked. They are used for Authorization, and grant the bearer of the access token access to the data for as long as the token has not expired.
Logging out is Authentication these are two very different concepts.
I mean what should you gain from a security perspective, while there is a Refresh token which is used to get a new access token as soon as you browse to the application?
You are again mixing Authorization (OAuth 2.0 access token refresh token) with authentication(open id connect, logging in a user).
Using OAuth 2.0 an application is granted authorization to access a users data they are granted an access token and a refresh token. The application can access the users data when ever it needs to without the user being present.
I don't see the profit from a security perspective when there is a Refresh token which can be used by whoever uses the computer and browse to the application.
This is the exact point of OAuth 2.0 it is there to grant an application access to a users data when the user is not present. It is not authentication.
When a user logs out from an OAuth2-based session, they might want to make sure that every application on the same machine can no longer do things on a users' behalf.
For example, perhaps your organization has a single-sign on system that spans several applications, some even third party. When the user logs out, you can't rely on applications to 'log themselves out'. Perhaps all they got is a a session cookie, sitting in a browsers' cookie jar waiting for the next request.
If I log out on a machine, I want the guarantee that nothing can still act on my behalf, not even for a minute.

How to log out using PKCE authorization flow?

If I have an app and an api. If the app logs in through authorization server and sends the authorization: Bearer xxx header with each request, the api can verify the token locally.
When the user logs out (through the auth server), but the token has not yet expired if someone retrieves this token they will be able to make requests (if the authentication of the token is done locally on the server), is that correct? If thats the case, why is such a logout flow considered secure?
Edit: Clarifying the main question: why PKCE flow is considered secure if when a user logs out their access token is still valid (given we do local token verification)
BEHAVIOUR OVERVIEW
With OAuth there is a greater separation of concerns than in older standalone web apps:
You log into UIs
This is externalised to an Authorization Server
An access token is issued with a fixed / short lifetime
Access tokens are used as API message credentials
The access token can potentially be sent to other components and used from there
When you logout:
You remove tokens from your app
You redirect to tell the Authorization Server the user is no longer logged into any UI
This doesn't invalidate access tokens
TOKEN STORAGE
Tokens should be stored in private memory or protected storage so that attackers cannot access them easily. Your app then removes tokens as part of the logout process so that they are no longer available for attackers to try to access.
THREATS
The OAuth Threat Model has a section on stolen tokens, where it recommends the above storage and to keep tokens short lived. The most common industry default for an access token is 60 minutes.
The main risk of a malicious party stealing a token is via cross site scripting. XSS risks are not related to logout. Security testing should be performed regularly to ensure that XSS risks are mitigated.
BALANCE BETWEEN SECURITY AND PERFORMANCE
It may be possible for the UI to tell the Authorization Server that a token is revoked. However, the API would then need to call the Authorization Server on every API request to check for token revocation. This would lead to poor performance.
API ARCHITECTURE
I always aim to use Claims Caching and introspection in OAuth secured APIs, since it gives the actual API best control, along with good extensibility and performance.
With this in place, if you really wanted to make access tokens non usable after logout, without ruining performance, your UI could perform these actions as part of the logout process:
Revoke the access token at the Authorization Server (if supported)
Call APIs to ask them to remove cached claims for the access token
Okta /introspect can tell you if active is true or false, you could check that on every request if you are not slamming the API https://developer.okta.com/docs/reference/api/oidc/#introspect
It's hard to get access to the token, that's probably a good reason why it's not per definition insecure.
However, providing a logout option is a good idea. OAuth2 has a 'revoke' feature to make sure that tokens are revoked:
https://www.rfc-editor.org/rfc/rfc7009
Not every server supports this.

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.

Should OAuth 2.0 be used for Authentication Timeouts?

Developers of a mobile application are using the timeout period of OAuth 2.0 tokens to check when the application must re-authenticate with the server.
This conflicts with my understanding of the proper use of OAuth 2.0 tokens, although I am not exactly sure that I am correct.
My understanding:
OAuth is not about authentication but about authorization, e.g. can this device access some resource on a server on behalf of a user. Authentication logically precedes authorization and is about confirming the user is who they say they are.
So a user presents credentials (username and password) and the server authenticates that yes, this user is Bob.
The application Bob has logged into wants access to some resources on the server Bob has been authenticated to - say data from an API. So the application requests an OAuth token and it is granted, and one of its attributes is how long it exists. The application and the server exchange keys, and the data between the application and server is encrypted using the key.
An intruder reading the plaintext communication will not be able to decode it without the key. However, if an intruder is able to get the key they will be able to.
This is where the OAuth token end of life comes in. We don't want to use the same OAuth token (key) forever, because if an intruder was able to get that token they can decript our communication forever. If however, we refresh tokens every x hours, then they could decrepit the information only for x hours (let's say 2 hours).
I don't think the OAuth token expiration time should be connected with how long the user remains authenticated. That is simply up to the developers. In our case, if the user has some device security (a passcode for example), then we can let them remain authenticated for a long time (months for example). If they do not have device security then I want to force them to re-authenticate after a reasonable amount of time of inactivity, maybe 24 hours.
Is this correct or not, and if not, what parts.
Thanks in advance.
Bryan
Your understanding on OAuth 2.0 is correct. In very abstract manner, the protocol define a way to obtain tokens, which can be used by a client to communicate against a protected endpoint.
RFC6749 mandate the usage of TLS when communicating with authorization server (the token obtaining) as well as when using it against an API/protected endpoint (Bearer token usage as defined in RFC6750). This protects token from in-transit attacks.
The OAuth access token is recommended to have a short life time. This is to avoid token stealing as well as token misusing that can be done by client. You can read more about best practices from RFC6819. Access token lifetime specifics can be read from here.
Now about selecting the correct life time. As you already figured out, using a refresh token is the desired approach to renew access tokens instead of having a long lasting access tokens. For example, a refresh token can be valid for few days while access token valid only for few hours.
But be mindful about the following,
+ Whether your application can obtain and secure a refresh token
For example, SPA cannot obtain a refresh token as it cannot store it for extended time. In such case you need to look for alternative mechanisms to renew the access token.
+ Is access token used against external domain
Using access token toward an external API increase the threat vector. For example, if you have a closed system (client and backend in one domain) then you may think of increasing access token life time. But not for an extended period like 24hours.!
+ Single sign on (SSO)
Instead of using long lasting access tokens, you can get the help of authorization server to maintain an SSO behavior on top of browser. This is similar to "remember me" you observe in modern login dialogs. Once logged in, browser maintain a cookie which lasts for some time (ex:- A week). The next time you use OAuth token obtaining flow, your authorisations server detect this logged in state, hence skipping login dialog. Of course, such approach must be decided on exact security/policy requirements.
In conclusion, use access tokens with reduced life time.Using refresh token is the desired approach for token renewal. But depending on the situation, you can choose alternatives as well.

AWS Cognito AdminUserGlobalSignOut does not invalidate Cognito cookie?

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