Skip to content

AWS Cognitio Logout Bug?

1

I have been working on integrating my web application with AWS Cognito + Google Workspace as my Idp. I was able to successfully authenticate using the Authentication Code Flow with PKCE. However, I hit an unexpected snag: the logout was failing to properly end the session with Google Workspace.

Now, Google [Workspace] does not support the Single Logout (SLO) flow, so it isn't surprising that after redirecting to the /logout endpoint that I was still logged into Google. What was troublesome, however, is that if I first logged out my user from AWS Cognito and then I explicitly went over to Google and logged out and then subsequently returned to my application to login that it would instantly log me in again without requiring validation from Google Workspace!

This is a security hole; if a user logs out of my app and then someone else uses the same computer to login, they would gain instant access to that previous user's account!

Fortunately, after a weekend of debugging, I was able to find a solution. Namely: before redirecting the user to the /logout endpoint, I first invoke the /oauth2/revoke endpoint to revoke the user's access + refresh tokens. Upon doing this, if I repeat the steps described above then the user will be forced to re-authenticate with Google Workspace.

What I can surmise from this is that the /logout endpoint is not properly revoking the user's tokens, as one would reasonably expect. Nor, again, have I found any documentation describing this as expected behavior.

Can someone from AWS please look into this and either update the documentation accordingly and/or fix this security bug? Much appreciated!

2 Answers
1

Thank you for bringing this important issue to our attention. You're correct that silently re-authenticating a user without requiring validation from the identity provider could lead to security vulnerabilities.

A few things to note here:

  1. Google Workspace does not support SAML SLO, so Cognito's /logout endpoint alone cannot fully sign the user out across both systems. [1]
  2. When a user logs out of Cognito, it only clears the session cookie, but ID tokens remain valid until expiration.
  3. Your solution of calling /oauth2/revoke before logout is a good workaround, as it invalidates refresh tokens stored in Cognito.

A few other things:

  1. Consider calling /oauth2/revoke on frontend logout in addition to backend calls.
  2. Set short ID token expiration times (e.g. 5 minutes) to reduce risk window if tokens are stolen.
  3. Add MFA for high-security applications to prevent token reuse even if stolen.
  4. Redirect to identity provider logout page in addition to Cognito logout.

Docs

[1]: SAML sign-out flow

AWS

answered 2 years ago

EXPERT

reviewed 2 years ago

  • Thanks Ibrahim. So it sounds like this id token that persists in Cognito is probably the issue; it's avoiding re-authenticating with the Idp on /login because that token persists. Is that a good, secure design decision? Can we perhaps add a configuration option to AWS Cognito to revoke this id token on logout? While my work-around is sufficient for the moment, I'd feel better if there wasn't the possibility for someone to pick-up a user's session after /logout without them having to authenticate.

0

May be this is already resolved but writing what I followed if anyone else finds it helpful. The important point here is that we have to call the /oauth2/revoke google endpoint with the access_token sent by Google. In the default scenario, Google will send this to Cognito when logging a user in but unless you map this token to any Cognito attribute, Cognito won't send it back to your frontend app.

So, we have 2 things to do here:

  1. Create a custom attribute in Cognito and map it to the access_token Google attribute. You can see this doc to understand how to map custom attributes.

Enter image description here

  1. Grab the custom attribute in the frontend and explicitly call the /oauth2/revoke endpoint with the access_token. Once step 1 is complete, I noticed that I am getting the custom attribute in the Cognito sent id token. Wrote the below code to call Google /oauth2/revoke in addition to Cognito logout.
import { signOut } from 'aws-amplify/auth'

const userSignOut = useCallback(async () => {
        const userSessionData = getStorage(USER_SESSION_KEY) as UserDetails
        removeStorage(USER_SESSION_KEY)

        if (userDetails.isBusinessUser || userSessionData.isBusinessUser || user) {
            const gaccessToken = userSessionData['custom:gaccess_token']
            if (gaccessToken) {
                try {
                    const formData = new URLSearchParams()
                    formData.append('token', gaccessToken)

                    await fetch('https://oauth2.googleapis.com/revoke', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded'
                        },
                        body: formData.toString()
                    })
                } catch (error) {
                    console.error(error)
                }
            }
           // signOut from Amplify which is used to communicate with Cognito
            signOut({ global: true }).then(() => setUserDetails(DEFAULT_USER_DETAILS))
        } else {
            setUserDetails({
                ...DEFAULT_USER_DETAILS
            })
        }
    }, [user, userDetails.isBusinessUser])

answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.