Renewing an API token in an ASP.NET MVC app - asp.net-mvc

I'm calling into a 3rd party API from my ASP.NET MVC app. This API uses a service/API token that you get by calling a "renew" API. It expires after 5 days.
If you call one of the service's APIs and the token as expired, you get an "api token expired" error and you can call the renew function.
I don't want to do this because it complicates my code by having to always check for the "api token expired" error and have the logic to retry. I'd rather just make sure the renew function gets called "relatively frequently but not on every request".
I do not want to use a timer or chron solution if I can avoid it.
I thought I read somewhere that IIS7+ automatically by default recycles the application instances on a regular basis. If this default is less than 5 days then I can just use Application_Start.

You can just use Application_Start and check that it has been at least x time since the last time you renewed the token, perhaps by storing a DateTime of when the last token was retrieved in a database or file.
You shouldn't have the app automatically starting up just for this.
(my advice would be to use the API in the way it is supposed to be used; you might run into a problem with the API provider if you request it too often, for example.)

Related

Google Calendar API v3 - Persistent Authorization with Code

Im wondering if anyone has any answers to this. If one follows the quickstart here:
https://developers.google.com/calendar/api/quickstart/go
we can get authorization from a user that allows us to do things with their calendar.
It seems the HTTP Client given back from the config handles calling the refresh token and keeping the client up to date.
First, as a side-question, does anyone know how long this is allowed to persist? I read in a doc somewhere that for unpublished apps/projects its 7 days, but it didn't specify a timeline otherwise. Is it indefinite or will this expire at some point (ie the refresh token runs out after 30 days). And is this avoidable at all?
now, the real question - if you take the service down entirely, ie for an update, and restart it, is there any way to opick up the authorization again? In the tutorial its writing a code to disk and reading as needed. In my case I just hold reference to the things I need in the application, so obviously when the service went down id have to reauthorize. I then tried writing the code to disk on a persistent volume and re-reading from that, but it doesnt get authorized - I guess because the new instance of the service has a new instance of the oauth config, and it wont accept the old code perhaps?
In any case, im wondering if anyone knows of a way to make this persist through ssytem restarts, or if the only real option here is to move the calendar service client to a small microservice on the side that we do not restart, and contact it from elsewhere as needed.
Thanks in advance!
The refresh token expiration is documented here. As you've noted, tokens expire in 7 days for projects in "Testing" status. Refresh tokens for projects in production last indefinitely, but there are some scenarios where they may get invalidated (user revokes access, token has not been used in 6 months, the account has over 50 live tokens, etc.). It's not mentioned but if you change your OAuth scopes you'll probably need to reauthorize as well.
This means that as long as you keep your refresh tokens and none of the invalidation conditions are met, you should be able to keep using them to get new access tokens even if your service goes down temporarily. But as mentioned in the documentation, you should anticipate the possibility that the token stops working and redirect the user to authorize again.
My guess is that in your case the refresh token stopped working for some reason (maybe the 7 days limit) and the application just tried to use the same expired token. The Quickstarts in Google's documentation usually handle the creation of the token file and how to reuse it, but they don't include the part where you have an invalid token and need to reauthorize.
References:
Google's OAuth2 Overview
OAuth2 for Web Apps

Using nodemailer & Google OAuth to send email, working for 7 days, but get invalid grant

I've been working to setup Oauth communication for an auto-emailing node.js web app using nodemailer. (I don't wish to use gmail's Less Secure Apps setting).
I've taken steps to get the client id, secret, and refresh token from the oauth playground, and have set up the web app to use a stored refresh token to request new access tokens when it first loads.
It is able to send emails (for about 7 days), then I get error invalid status code 400 on client side, and/or invalid grant on server side.
Going back to google playground and getting another refresh token, then updating it in environment variables, solves this for another week. But I'd like to solve this indefinitely.
I read somewhere "A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of 'Testing' is issued a refresh token expiring in 7 days"... so last week I switched the app to "In Production" (at console.cloud.google.com) and tried having it verified with google. This week, the same issue has recurred suggesting that wasn't the right fix, or that it wasn't yet verified with google.
I don't know if this was done correctly, nor do I know if this is the true solution to this expiring/revoked refresh token, or invalid grant.
I've also come across these explanations:
The user has revoked your app's access.
The refresh token has not been used for six months.
The user changed passwords and the refresh token contains Gmail scopes.
The user account has exceeded a maximum number of granted (live) refresh tokens.
The client has reached a limit of 50 refresh tokens per account if it's not a service account.
(I didn't make ANY changes during the week, so...not sure why these would have changed)
Is the issue the refresh token?
Or the status of the application?
Would it be dns/cname/cloudflare server issues?
For those who have the same issue in the future:
It turned out that google verification wasn't necessary.
It seems like the refresh token expiring after a week or 7 days was due to the placement of the oauth2Client.setCredentials() function call and accessToken variable.
Calling setCredentials() and obtaining the access token INSIDE the SendEmail() function (at runtime, just before sending email, rather than at application start/spinup time) seemed like it enabled the code to more dynamically generate the tokens it needed. After 12 days, it still seems like its working so I'd call this a success.
My guess at why it wasn't working before was because setting credentials outside of a function meant that code only ran once on server/application startup. It would then store the obtained access token in a const.
The access token would eventually expire, and even if called again/later inside of a function to obtain a new access token, it would be unable to change the value of a const property/variable, and so the call would inevitably fail after a week when it failed to renew.
Hope this helps anyone else having a similar issue.
My apologies for the run-on sentences.
There are a lot of causes for invalid grant it sounds to me like your refresh token is expiring.
If your project on google developer console is still in testing, has not been moved to published and has not gone though the google application verification process then refresh tokens have a max two week life span after which they will expire which may explain your invalid grant. The thing is there is no official word from google that this is happening its just what a lot of developers are seeing these days.
Another one is with gmail scopes if the user changes their password this will also cause the refresh token to expire.

How is access token refreshed / acquired when using API Client Library for .NET?

I have one quick question related to "acquiring a new access token upon expiration". I have read some tutorials where people write code to manually request a new access token.
In my case I wrote an ASP.NET MVC app to access Google APIs, such as Gmail API, and I am using API Client Library for .NET for that.
After OAuth 2.0 authorization I get back the result object of type AuthorizationCodeWebApp.AuthResult.
Where result.Credential.Token contains AccessToken and RefreshToken properties.
I save the refresh token in my web.config the very first time when it comes back (after the consent screen). All next requests dont have a refresh token, only an access token that expires after 1 hour.
So, my question is - before I make a call to instantiate a Gmail Service, I assign previously saved refresh token:
result.Credential.Token.RefreshToken = WebConfigurationManager.AppSettings["RefreshToken"];
var service = new GmailService(
new BaseClientService.Initializer { HttpClientInitializer = credential });
When result.Credential.Token.AccessToken expires, does Gmail API (or any other API Client Library for .NET) acquires a new access token automatically if result.Credential.Token.RefreshToken was assigned a valid refresh token value previously saved, like in my code sample?
Thank you!
UPDATE - More clarification to my question With the same refresh token, how many times I can aquire a new access token when making calls to Google API?
I will explain: access token expires in 1 hour, right.
If I keep making calls with, lets say, 10 minutes intervals to Gmail API (for example), after 6 calls (1 hour limit), Gmail API will use my refresh token to acquire a new access token. After 6 more calls (1 more hour) the whole thing repeats itself. Question - is there a limit to it? Remember, I am not changing my refresh token. Same refresh token is being used to acquire a new access token. And for how long this repetitive calls may continue without any error?
UPDATE AFTER THE TEST
I let my application run on my local machine in Visual Studio DEBUG mode trying to catch any exception, NO Human interaction.
The application kept receiving AJAX calls to Gmail Action with 2 minutes interval, everything was working fine, I went to the gym, came back 2 hours later - oops, Visual Studio debug is open on this Token has been revoked exception, here we go, so it's clear the token was revoked by the Google API service, as you can see from the Debug window. The only question remains - why, since there are no specific details are provided, there is no Inner Exception just that general error message and no reason, but the source is clear - Google API, we can even see it came back from
Google.Apis.Requests.ClientServiceRequest`1.Execute() в
C:\Users\mdril\Documents\GitHub\google-api-dotnet-client\Src\GoogleApis\Apis\Requests\ClientServiceRequest.cs:row
96
I am guessing the service shuts down (revokes a token) after N number of calls, maybe within certain interval. If some one knows the limitations of Google API in terms of number of calls or time intervals between calls, please let me know.
It seems that Matthew Riley, the custodian of Google API on github, coded some logic to revoke a token based on some criteria: https://github.com/google/google-api-dotnet-client
Long response to comment :
One question though: can this be done indefinitely long, unlimited number of times, or I will get an error at some point?
Refresh tokens can be come invalid for the following reasons:
user can revoke it in there google account.
if a refresh token isn't used for 6 months to get a new access token it will expire automatically.
If a user authenticates your application you get a refresh token if they do it again you get a different refresh token. Both will work. you can do this up to 26 times. on the 27 th time the user Authenticates your application the first one you got will expire. You can only have 26 live refresh tokens. (DONT ASK how I know this! "#¤%&)
So assuming you don't reauthentcate your application to many times, use the refresh token at least once every six months. You can use it as many times as you want.
Update for comment:
I think you are still confused. Access tokens expire after 1 hour. Refresh tokens only expire for the above reasons you can use them as many times as you like. To get a new access token.
However you can only have 25 working refresh tokens.
Lets say I have a windows service application that backs up files to a users Google drive account. A user installs it on a server and authenticates it and gets a refresh token. Every night the windows service runs and backs up the files to google drive, it uses the refresh token to get a new access token.
Lets say this user really likes my auto super imba backup service. He installs it on another server. He gets another refresh token and the application goes about its business uploading files at night
Lets say my super user really has a server farm he installs my application on 25 servers. Those applications will be able to get new access tokens forever.
However if this crazy user installs it the 26 th time on a different server getting a new refresh token for this server. The first server they installed it on will stop working because google only allows you to have 25 outstanding refresh tokens for an application.
This is user application based so you can have any number of users each with a max of 25 refresh tokens

Doorkeeper refresh token and concurrency

In the current implementation of doorkeeper, When the access_token is refreshed doorkeeper also sends a new refresh_token.This is a valid implementation but it becomes problematic when there are concurrent apis calls from my client side (ios, android) calling to refresh the access token at the same time. This means that there will be at least 1 thread ending up with expired tokens that it cant refresh.
Anyone has solution for this race condition?
We've solved this before (not with doorkeeper) a couple of different ways.
Request Queue:
On our mobile apps we've implemented a request queue, and just before a request is made we check if the token needs to be refreshed then we pause the queue, refresh the token, then unpause again. No changes to the server required in this case
This has tradeoffs (you need to sync your request threads etc), but is pretty reliable at stopping the refresh contention without needing to modify the server.
Refresh jitter and JWT:
Since we are using JWT (where the access_token expiry is written into the token and not revoked at the server end), you can add a random number of "jitter seconds" to the refresh expiry each time you check. This decreases the likelihood of two requests trying to refresh at the same time. I used this in an AngularJS app that would get all confused with several tabs open. There was a random chance one tab would refresh before the rest, while the rest could continue to use their existing access_token until the new one was returned and updated.
This would probably also work without JWT if you can manage to get your access_tokens to stay valid when their corresponding refresh token is used, which would allow the 'other' requests to continue to use their 'old' token until the next time.
It's not entirely foolproof, but reduced the likelihood enough we were happy with it.
Expiry buffers for tokens:
The last way was when a refresh was executed, don't actually expire the token for another few seconds later so any 'concurrent' threads just get the new token returned. This was easy enough when I'd written the server component from scratch, but might not be so easy with doorkeeper. I think you'd get more milage from the other two approaches.

Google OAuth's access token's expiry timezone

I recently switched to the Google+ Sign in OAuth2 hybrid approach.
When the request code is exchanged for the access token, the expiry time and created time is sent back along with the access token in seconds.
I need to know the sent timezone is. I need this to make comparison with my server's time and be able to deduce if access token has actually expired.
What's the timezone or how do I determine it?
The token bundle sent back does not include an actual expiration time, but it does contain the number of seconds for the expected life of the token. If a time is being attached to it, it is being attached by the local library.
That said - you can't necessarily trust this number. There are a number of reasons why the token may have been revoked or is treated as no longer valid. So while you can use it as an estimate of when you'll need to get a new one - you should also handle the case where you use a token and you get an authentication error, forcing you to refresh the token and try again.
My bad.
I just went through the Google PHP APi client library. Only to realize the created field was set within the library (on my server) in Google_Auth_OAuth2's authenticate method.
So it is safe to use $client->isAccessTokenExpired() instead to try to do one's computation. Works with local time (I guess :))
Thank you.

Resources