New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cognito session refresh does not refresh Google access token #3619
Comments
I have also now updated my code to use Auth.federatedSignIn( { provider: 'Google' } ) per the latest guidance from AWS Amplify. The results are the same: a new set of Cognito User Pool access and ID tokens are obtained by Amplify, but the custom attribute that holds the mapped Google access token remains unchanged. This is confirmed from inspecting the currentAuthethenticatedUser as well as looking in the Cognito User Pool using management console. AWS Support team offers this as a workaround: prompt the user to login again... unusable for us because the user experience will be atrocious. |
Hi @tcchau Thank you for the very detailed report! 😃 This is a problem in the documentation. The docs should make clear mention of:
The suggestion that I have for you, is to capture google's refresh token too in an attribute and use the Pre Token Generation Lambda Trigger to listen for I'll make a note to fix the docs. |
@manueliglesias Thanks. I had to go work on a different project the last couple days and didn't have time to check back on this. Here's what I've found, and perhaps this will help others who have requirements to work with both AWS and Google services:
|
@manueliglesias I wonder if User Pool can provide a mechanism for its user to achieve this. I knew this requires User Pool to send the request to Google with an
This basically makes User Pool in the whole solution as a sub-optimal choice. In other words, we want to use User Pool in the solution because of its other features; but the limit of not able to get refresh-token in the custom attribute made it really hard to solve some specific problem. Not sure if Cognito team has any reason not supporting it. |
@tcchau I know this has been closed for quite a while, but did you ever figure out a solution here? |
@jmkmay The solution I settled on was the one mentioned in my comment above. Basically, since I need the Google API client to access other Google services anyway, I didn't mind using it to manage automatically refreshing my Google tokens as well. |
@manueliglesias I guess this is still not clear in the documentation. Lots of confusing stuff in there. If I add an identity pool to my auth configuration, will it refresh google/Facebook tokens? |
Hi, @bredele:
I had meant to use this approach originally because it was mentioned in a forum at some point. I never did get this to work properly at the time. This was quite some time ago, but I think either the refresh token couldn't be mapped to an attribute, or if it did map, it never got updated but stayed at the value that was initially set. Again, this was quite some time ago, and as I found a usable workaround, I never re-visited this. C. |
Hi, @tcchau
Can you make your solution a bit more clear, please. That would be very helpful if you could show a couple lines of code to get the idea how you manage all this. |
I tried to express my answer in general terms because your particular situation will almost certainly require very specific code. But I'll try to outline in a different way. Recap... Prerequisites: You're using Cognito User Pool to manage your user accounts, and have configured Google as an OpenID IDP properly, and you've also configured Cognito hosted authentication to facilitate sign-in using Google. Once the user has authenticated using the hosted authentication mechanism, your frontend will have received two things: all the Cognito tokens necessary for accessing the AWS API, and also the access token from Google for accessing the Google API. These are stored in a combination of localstorage and cookies. The problem is that the Google access token will not be automatically refreshed, and you do not have programmatic access to the Google refresh token in a clean way; you can try to reverse-engineer the localstorage or cookies, but that approach is going to be very brittle. The Google API Javascript client, however, promises to automatically refresh access tokens so you won't even have to worry about it. So the trick is, instantiate the gapi object, then associate the instance with your already-authenticated Google account -- recall the user has already signed in using their Google account.
<script
type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=<YOUR_PUBLIC_GOOGLE_API_KEY>&libraries=<GOOGLE_LIBRARIES_YOU_USE>"
></script> This makes a globally available object named 'gapi'.
const identities = cognitoUser.signInUserSession.idToken.payload.identities;
const googleIdentity = identities.filter((identity) => {
return identity.providerName === 'Google';
});
const googleUserId = googleIdentity[0].userId;
const auth2Params = {
client_id: getConfiguration('google').clientId,
immediate: true,
login_hint: googleUserId,
};
gapi.load('client:auth2', () => {
gapi.auth2.init(auth2Params);
}); The gapi client will reach out to the Google auth servers to validate the Google tokens stored in localstorage and cookies and will understand that the user associated with the Google ID has already authenticated. They will not be prompted to login again! Hope that gives you enough of an idea what we're trying to do here. |
Thx @tcchau this solved it for me, too! Just a side note: it is MANDATORY to use the hosted UI, this is what I skipped even though it's in the solution proposal, but can be easily overlooked (at least I did). It doesn't work when you use We're using this in a React app running inside an Electron as a desktop application. Using https://www.npmjs.com/package/gapi-script helps accessing the gapi object. |
@tcchau is there a similar approach on the server? I couldn't find a similar login method for the nodejs client and there are no cookies and localStorage but maybe |
@rickiesmooth Not knowing more about your requirements, I can't say much more, but... I've discovered that the attribute mapping between OIDC providers and Cognito works much more reliably now. In my previous comments, I mention that mapping Google's access token and refresh tokens doesn't seem like a viable approach because it doesn't seem like they are updated over subsequent auth events. That does not appear to be the case anymore. I am using this method to access the OIDC's access tokens in another project I'm working on now and it's fine. Can't comment on the refresh token as I'm not using it. What this means for you, is that you should be able to send along the access token from Google to your server, so that your server can make use of it to access Google APIs! Hope that helps. |
@tcchau that's exactly what I want to do! Access Google API's on the Cognito user behalf. Currently I'm using the Google Identity provider (not OpenID Connect (OIDC)). Forgive my ignorance, but does that mean the access tokens will never be expired when mapped between the Google Provider and Cognito? |
|
Hey guys, there are some Amplify docs on this now: https://docs.amplify.aws/lib/auth/advanced/q/platform/js/#facebook-sign-in-react-native---expo:~:text=Google%20sign%2Din,68 , which could help when combined with #3619 (comment) |
But how can I do it with the new Google Identity API since the one in the example is deprecated. There is no login_hint there. |
Describe the bug
Per https://aws-amplify.github.io/docs/js/authentication#react-components we expect that when the Cognito user session is refreshed, that the associated Google access token from a login using Google would also be refreshed. However it is not.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
We expected that the Google access token would also be refreshed, per the AWS Amplify documentation.
Screenshots
N/A
Desktop (please complete the following information):
Smartphone (please complete the following information):
N/A
Additional context
Sample code
Code to open hosted UI:
Code to process hosted UI callback:
Code to refresh Cognito tokens:
You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app.
Initial login:
Tokens being refreshed:
Error from Google once the access token has expired:
Final Comment
I don't know if
AuthClass - cannot load federated user from auth storage
is significant. I find it strange that I have to use attribute mapping to access the Google access tokens. Maybe I'm not setting up Cognito correctly and I should be able to get the federated user information through some other means, and because it's missing, the refresh is not working?The text was updated successfully, but these errors were encountered: