I've been using google API to send emails from the server in my node.js project.
I've setup credentials and created a refresh token and access token and have been using the same for over 6 months like so.
oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris);
oAuth2Client.setCredentials({ refresh_token, access_token, scope, expiry_date });
gmail = google.gmail({ version: 'v1', oAuth2Client });
gmail.users.messages.send({ /* email details */ });
The expiry_date I'm sending is the one I received when I created my tokens the first time and so the date is a past date (over 6 months).
I remember reading that the access token expires after sometime but I'm not sure when my access_token will expire or how I'd go about creating a new one.
My emails are still being sent so I'm a little confused as to why it hasn't stopped working yet.
So my questions are essentially
How do I find out when my access_token will expire.
Once it does expire how do I create a new one. While setting all this up the first time I remember doing it in playground but I'd prefer to set up the access_token creation process in the server code itself if I can.
Access tokens expire after one hour. The best and only way to know if it has expired is to try it if the access token has expired the API will return an error to you.
Refresh tokens on the other hand for the most part will not expire. Your code is most likely using the refresh token properly to request a new access token when ever it needs one. This functionality is built into the Google apis js client library for you and is not something you need to consider.
how a refresh token can expire
the user can remove your access via their Google account.
If the access token has not been used in six months google will automatically expire it.
If you request authorization (Show the consent screen) to the user you will get a refresh token back. If you do it again you will get another refresh token¸ both will work. You can have up to fifty outstanding refresh tokens for a given user once you have hit that mark the first one will expire.
Weird bug from a few years ago that when daylight savings time hit a lot of Google refresh tokens were automatically expired due to some weird bug on their end which has not happens again since :)
Related
I thought I'd try posting my problem here given the non-existent support that Linnworks provide.
I've created a private embedded app within Linnworks that displays orders in a spreadsheet format. The app is built with Vue.js and uses axios to pull the data from Linnworks APIs. Everything is working as it should be here, except that I'm only returning 100 orders at a time to keep things quick.
I've added a "load more orders" button which appends an additional 100 orders to the end of the sheet, but after a period of inactivity, this causes a "401 unauthorised error" because the token has expired.
Because it's an embedded app, Linnworks store the token within the src of the iframe when the app is initialised, so when it has expired, it doesn't get physically refreshed by the system.
<iframe src="https://example.com/sheet.html?token=9b11e8ff-4791-aca5-b58d-f6da84e996a6"></iframe>
Is there a way of getting the refreshed token without reloading the entire app?
Tokens have a default TTL of 30 minutes, just poll the API with a simple method like /api/Main/Ping to keep your token/session active
I got the following response from Linnworks, which fixed the problem:
After further investigation, this appears to be due to the the pinging of the AuthorizeByApplication call. To help reduce the risk of being returned a 401 Unauthorised "Token has expired. please re-verify the user", it is recommended that when the application is opened, call AuthorizeByApplication and save the response.
Once the session has been created, AuthorizeByApplication should not have to be called again. The token returned in this session has a TTL of 30 minutes. If this token is used in a further call, the TTL of the token is reset back to 30 minutes. Therefore, as suggested in the response of your Stackoverflow question, briefly calling "api/Main/Ping" will reset the 30 minute TTL with little impact on your applications performance.
To Prevent Applications From Using Expired Tokens:
Upon launching application, call AuthorizeByApplication and save session response.
To keep the session from ending, call "api/Main/Ping" using the saved session token to reset the TTL of the saved session.
For any calls made by the application, use the original saved session token.
I set up a sessionless app that uses OAuth2 password grant authentication. When a user logs into my app with a username and password I save the access token in sessionStorage which is valid for 30 minutes. I also save a refresh token in sessionStorage in case I need to extend the session longer than 30 minutes. The refresh token is valid for 30 days.
If the 'remember me' checkbox is selected on login I save the access and refresh tokens in localStorage so they will persist as long as the refresh token is valid.
Both of these seem to work fine except for a couple of issues:
If the browser is left open and the user doesn't log out the session could potentially last for 30 days.
sessionsStorage doesn't persist between windows/tabs so if the user opens a new window they need to log in again. This is not an issue when the 'remember me' checkbox is selected since localStorage does persist between windows.
I think using refresh tokens is not safe for JavaScript applications - you need to access the /token endpoint and authenticate using the application's secret. But the secret gets public in such applications.
I would prefer the OAuth2 implicit flow and getting new token from the /auth endpoint with prompt=none parameter (from OpenID Connect). But with the implicit flow, you would either need to get a longer living ID token (and ask for an access token with the ID token later) or to implement the "remember me" at the OAuth2 (better option - can be used by any application). That would also solve the problem #2 with passing tokens between tabs.
By the "session" you mean using the refresh token to generate access tokens for 30 days? If that's a problem, you can implement some activity detector which would log the user out if there is no activity for e.g. 30 minutes.
It's possible to use the localStorage as a kind of message passing service, so you can keep the tokens in the sessionStorage, but a new tab can use the localStorage to request the token from existing tabs. For more info see http://www.codediesel.com/javascript/sharing-messages-and-data-across-windows-using-localstorage/
Code example from the linked article:
function eventListener(e) {
if (e.key == 'storage-event') {
output.innerHTML = e.newValue;
}
}
function triggerEvent() {
localStorage.setItem('storage-event', this.value);
}
window.addEventListener("storage", eventListener, true);
data.addEventListener("keyup", triggerEvent, true);
The workflow would be like this:
New tab is opened and writes an arbitrary value to the localStorage with a key indicating that it needs a token. The key can be "newTabOpened". The new tab starts listening to changes of another key "oauth2token".
The existing tab listens to the changes of the "newTabOpened" key and as a reaction, it writes its token value under the "oauth2token" key.
The new tab reads the token and removes it from the localStorage.
I am currently having trouble with the ADAL.js (v1.0.7) library. When I load my app after a decent period of time I get a login error stating "Nonce is not same as undefined." After looking over the code, I am wondering if I am missing a best practice. To my knowledge, I have followed the suggestions of #vibronet here. Should I be refreshing the user profile, or logging out, or something else?
My configuration looks like:
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: 'blahblahblah.onmicrosoft.com',
clientId: 'GUID',
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage'
};
this.authContext = new window.AuthenticationContext(window.config);
var isCallback = this.authContext.isCallback(window.location.hash);
this.authContext.handleWindowCallback();
if (isCallback && !this.authContext.getLoginError()) {
window.location = this.authContext._getItem(this.authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
If there has been an extended period of inactivity, the error occurs after calling this.authContext.login(). In order to get the error I call this.authContext.getLoginError().
I get why the nonce is different, but I want to "reset" it or cause a brand new login to happen.
Please let me know what other relevant information I can provide.
Update:
Seems like solution has been provided in blog post you provide. below is the quote.
The trick is to go back to the authority asking for a token, like we’d
do in the roundtrip apps scenario, but doing so in a hidden iframe. If
there is still an existing session with the authority (which might be
represented by a cookie – but it is a cookie in the domain of the
authority, NOT the app’s) we will be able to get a new token without
any UX. There is even a specific parameter, prompt=none, which lets
Azure AD know that we want to get the token without a UX, and if it
can’t be done we want to get an error back. Here there’s the request.
Previous answer:
i am not fully follow what your code does. but as from blog post, seems like underneath you are using OAuth 2.0
when you said error happen when there is period of inactivity, my guess is token has been invalid, and you will need to refresh the token. Not sure if there is a way for you to refresh it. But normally on server side once you authenticated, OAuth 2.0 provider will hand over you a token and a refresh token, if token is expired, you can use refresh token to get a new one.
I am using the following procedure to refresh linkedin oauth2 access tokens
https://developer.linkedin.com/docs/oauth2#refresh
After initiating the oauth procedure in the browser, the dialog is skipped as described, and a new code is issued which I then use to obtain a new, different access_token. However the expires_in field ( seconds till expiration ) is lesser than the one in the previous access_token it is in fact referencing the same expiration date.
This means that the expiration date effectively has not been extended, Which is the purpose of refreshing the access token.
Does refreshing an access token extend the expiration time ?
Or is there anything I am missing here ?
( perhaps the expiration date can only be extended after a certain time of usage ? )
The expires_in will always be the same as the previous access_token because expires_in is just the number of expires that the token will be valid for. I don't know what LinkedIn return for this value, but I'm guessing you are seeing a nice round number each time?
https://www.rfc-editor.org/rfc/rfc6749#section-4.2.2
expires_in
RECOMMENDED. The lifetime in seconds of the access token. For
example, the value "3600" denotes that the access token will
expire in one hour from the time the response was generated.
If omitted, the authorization server SHOULD provide the
expiration time via other means or document the default value.
I've created a website or Instagram bot that auto likes and follows based on tags.
I've abide by Instagrams server side auth and enforced signed header and can currently like 100 images per hour and follow/unfollow 60 times an hour.
The current limit per user is 350 likes/hour, I'd like to hit close to that, around 250-300. But each access token is only worth 100/hour.
So my question is, how can I release my current access token so that I can get a new one?
The website is http://instapromobiz.com if you want to try it out.
You can't avoid the hourly rate limit per user by getting a new access token for that user. You'd need to get an access token for a different user or queue up requests and make them after an hour has passed.