Open LindaLawton opened 3 years ago
I'll reproduce later this afternoon and see what options are there to avoid/mitigate this. I'll update here when I know more.
Emailed you a drive link to what i am using.
I tried adding a messy catch around it just to try and clear the cookies it didn't work.
Thanks, I'm looking at a couple other things on my plate first. I'll still try to get to this later today.
No rush when you have time, I was just testing this while finalizing the video going up tomorrow and ran across this .
Just as a note, the linked you shared earlier, I think that by mistake you just copied the standard VS template for a ASP.NET Core 3 App, no code configuring Google.Apis.Auth.AspNetCore3 that I can see, or a dependency either, etc. But no worries, I'm now reproducing and will post here shortly. Thanks.
Did you check startup.cs? It should all be there. This is the video I mentioned How to get a google users profile information. (ASP .Net Core)
Yep, I downloaded it twice in the morning and just now before replying, I just see the standard template, standard Startup etc. But no worries, I've got working code, was flagging mostly in case you are sharing that somehwere else.
When a user revokes their permission for an app, code using Google.Apis.Auth.AspNetCore*
may see exceptions in any of three different places, and unfortunately the exceptions are different each time. The way to handle them so as to attempt a re-authorization is the same, basically, we want to log out the user.
The first is the one initially reported here, an exception will be thrown when using the revoked tokens to make an API call. That can be dealt with as follows
try
{
var calendars = await service.CalendarList.List().ExecuteAsync();
}
// You can also check ex.RequestError for filtering down the exception.
catch (GoogleApiException ex) when (ex.HttpStatusCode == System.Net.HttpStatusCode.Unauthorized)
{
await HttpContext.SignOutAsync();
// This is not necessary, the exception may be rethrown here and handled in the normal way that your application
// handles exceptions. Or you may redirect straight to the home page,
// or to a special page that says "You have been signed out", etc.
return RedirectToAction();
}
The second one is when fetching the credential itself from IGoogleAuthProvider
. If the access token needs refreshing, then an attempt will be made to do so, but since the refresh token has been revoked, it will fail. This can be dealt with as follows:
try
{
// auth is IGoogleAuthProvider
GoogleCredential cred = await auth.GetCredentialAsync();
}
catch (InvalidOperationException ex)
{
await HttpContext.SignOutAsync();
// This is not necessary, the exception may be rethrown here and handled in the normal way that your application
// handles exceptions. Or you may redirect straight to the home page,
// or to a special page that says "You have been signed out", etc.
return RedirectToAction();
}
The third one is when doing incremental auth, either via attributes or via code. This exception happens before reaching the controller, it happens in the auth pipeline, so it cannot be caught on controller user code directly. In this case user code should include an exception handler page that checks for a Microsoft.Identity.Model.Tokens.SecurityTokenException
and calls HttpContext.SignOutAsync()
and then shows a message or similar. This approach can also be used for the other two cases, checking for the appropiate exceptions.
This is all of course far from ideal, and it can probably be improved. But it will requiere careful design so as not to cause side effects. We don't have bandwidth to look into it for the next 3 to 4 weeks. I'll leave this issue open as a low priority feature request. Also note that this is a corner case, given that authentication cookies are not persistent cross browser sessions by default, we are talking about a user that has authenticated, goes and revokes the tokens, and comes back to the same session that they authenticated in to try an use the app again.
I also wante to comment a little on this:
At this point if i had been using a installed application the library would pop up and request access again.
That's not exactly the case. When a user has revoked the tokens:
GoogleWebAuthorizationBroker.AuthorizeAsync
) before will keep holding the old tokens, so they will fail access token refreshes and client services that were created with these credentials will fail all operations.IDataStore
will hold on to the old tokens until the first attempt at using them (refreshing the access token or calling an API) has failed, at which point, they will be removed from the IDataStore
effectively "signing the user out". This means that even credentials (and depedent service clients) created after the user has revoked the tokens may be created with old tokens and thus be invalid.IDataStore
, the first credential created (via GoogleWebAuthorizationBroker.AuthorizeAsync
) will trigger the normal auth flow, prompting the user etc. This credential and all subsequent ones will be valid.GoogleWebAuthorizationBroker.ReauthorizeAsync
on them.But this is all more easily handled by client code, with a retry for instance that recreates the client service after there's been a failure. If you have such retries already, then it will seem like the auth library is automatically prompting after a token has been revoked.
@amanda-tarafa if we are talking about a rewrite. Can we chat about coming up with a method for storing credentials like the old Idatastore. We need an option for linking it to identity storage, (ef netcore, or home grown) and persisting the refresh token.
No I don't think it would be a rewrite, just to provide helper methods and similar to make it easier to handle this case. I'll know more when I have the time to work on it.
Also, I don't see why Google.Apis.Auth.AspNetCore* wouldn't work with Identity. I don't remember having tried it, but I believe these libraries were implemented with that in mind. When I get to this issue, I'll try it and post back about it.
Also, if your main interest is to persist the refresh token, take a look at:
(As a side note, if you have questions or run into issues with storing tokens or using in conjunction with Identity, please do create new issues for that to keep this one about revoked tokens. Thanks!)
Also, I don't see why Google.Apis.Auth.AspNetCore* wouldn't work with Identity. I don't remember having tried it, but I believe these libraries were implemented with that in mind. When I get to this issue, I'll try it and post back about it.
I haven't tried it either Its on the list, maybe we can come up with an example together.
Sounds good, I'll let you know when I start looking into it. It'll be a few weeks though.
That's fine i have a huge backlog of tutorials and videos i am working on now.
hi, I have the same issue "How to catch authorization fail, clear cookies and request access again" I wonder if is there a solution for it..
@meof-coding You need to follow three different approaches as described in my https://github.com/googleapis/google-api-dotnet-client/issues/1816#issuecomment-811769827.
I understand this is far from ideal, but we haven't had the time to improve the error handling side of things. We've kept the issue open though as we would like to revisit if we have the time in the future.
I've used this by this guide-line on Windows Form SheetService for a while.
It seems like work for personal Google account, but suddenly unavailable for Workspace account.
@ycidx: It's not clear whether your issue is actually related to this one - it seems unlikely given that you're talking about Windows Forms and this issue is about ASP.NET Core. Please file a new issue with as much information as possible, in particular more details than "suddenly unavailable".
I have a simple asp .net core application which was built based upon our sample code.
I authorized the user and accessed the users profile data. Then i went to my account permissions and removed the applciations access.
At this point if i had been using a installed application the library would pop up and request access again. In this case the application crashes.
Clearing the cookies in the web app did fix this.
My question is this an issue with the library that we are forcing a clear, or is this something we need to recommend that users catch some how to force a clear of the cookies so that the user does not get an error in this manner?
Im really not a web dev so i guess i am fishing for opinions on how best to advice our developers.
I have cross posted this here How to catch authorization fail, clear cookies and request access again