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.
Related
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 :)
I'm using social authentication using the vue-google-oauth2 library. It works fine as I am able to authenticate my self and I receive a token from the backend too.
When initially I log in, and by using a function that is part of the vue-google-oauth2 library that I'm using to check if it says that I'm authorized or not, it gives the following response in my browser's console:
this.$gAuth.isAuthorized
true
When I then refresh my browser page, and since I've placed a debugger command in my code, and I print the same function again,
I get the following response:
this.$gAuth.isAuthorized
false
What can I do to ensure that switching tabs, reloading page or refreshing it won't make this happen? Or is this what is actually supposed to be happening?
Have you looked at saving it in as session data? Im not to familiar how Angular state works, but when you set original state you can look for the session key "authorized" and if it doesnt exist set auth to false, if it exists set it to the value.
localstorage.getItem(item)
and
localstorage.setItem(item)
There is also the option of making a component that handles the google auth and sends it to the state.
From the library documentation for vue-google-oauth page you linked it says you need to send that code back to your backend server to create a token to stay signed in, so it's behaving as expected. From here (https://www.npmjs.com/package/vue-google-oauth2#usage---getting-authorization-code) it states :
The authCode that is being returned is the one-time code that you can
send to your backend server, so that the server can exchange for its
own access_token and refresh_token
In other words, you need to do something with that code to make it persist in your app, otherwise it's just a one-time code, so looks to be expected.
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 have an ASP.NET application that is using forms authentication with a timeout set to five minutes. On my page I have a button, that when clicked, makes an AJAX call to an operation that lives on the service named in my .svc file. How do I know, from the client javascipt that the application has timed out? Or, how can I detect this in the global.asax; maybe in the application_beginrequest?
If you're talking about the session timeout. When this occurs, the IHttpSessionState.IsNewSession property should be set to true.
If you're referring to the auth timeout, then you have to check the AuthenticationTicket for expiration.
A variation on your approach: have a separate client script that first checks for authentication expiration by requesting a special page/handler which returns JSON structure to indicate the authentication status of the current user. Only after knowing that the user is still active do you then run your main ajax action. It's one more request but keeps you from entangling the timeout logic with the main ajax logic. You can also use separately in a "warning, your session will time out in x minutes" popup.
See this question and my answer there for more details about how to set it up, but the key point is that if you don't want the check for expiration to extend the sliding expiration you have to configure the expiration page/handler as a separate virtual directory with forms authentication set with slidingExpiration=false.
I'm having a lot of difficulty getting strophe's 'attach()' function working.
I am working on a social network where users will be surfing pages and at the same time keep their chat connection on. I don't want to reconnect/reauthorize on every page so as per this link, http://groups.google.com/group/strophe/browse_thread/thread/430da5e788278f3a/93c48c88164f382f?show_docid=93c48c88164f382f&fwc=1, i am storing the SID and RID into a cookie onunload.
On the next page when i try to use the new SID and RID (after incrementing it by 1) my session is already destroyed. Ejabberd reports "Error on HTTP put. Reason: bad_key"
WTF is happening?
Without more logging information from ejabberd or Firebug, this will be hard to diagnose. Is the correct RID actually stored in the cookie? What does ejabberd think is the last stanza you sent, and what RID value does it have? What is the first stanza and the first RID value on the new page? How long between those two stanzas?
Updated: The reason the session gets canceled is due to the security model of BOSH. Effectively, the SID and RID pair are secret. If you know the pair, you can attach to the session. In order to keep people form being able to guess, the RID is picked randomly from a very large space. If you send an RID outside a very small window from the current RID, it will disconnect the session. The window is usually (RID, RID + 5) or so.
I managed to solve the problem.
The rid was being double incremented between the page loads. By incrementing it only once the session attach started working.
I don't know why the session got cancelled, but here's what happened :
Because the RID is +2 more than the previous ones, ejabberd stores the request in buffer and does not forward it to clients
The next 2 requests also get stored
The one after that causes ejabberd to cancel the session
Any clues?