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.
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 would like to add a Sign In with Google and a Sign Out button to my Chrome extension.
One technique that uses chrome.identity.getAuthToken for Sign In is described in this tutorial. It works great! When the button is clicked, it shows a popup for authentication and authorization.
But how should I implement the Sign Out button?
I tried to use the removeCachedAuthToken method in the on-click handler of my Sign Out button. With this, the sign-in functionality doesn't work as expected. After, when I pressed the Sign In button again, I got a new token directly without a popup asking the user to authenticate and authorize my extension. I would like users to be able to change their account by signing out. With this technique, that's not possible. How should I implement the sign out functionality to allow for this?
This has been bugging me too, until I realized that I got mixed up by the difference between sign-in and authorization, sign-out and revoking access.
First, let's not get caught up in the name of the button. Yo may call it Sign Out, but what you actually want to achieve is to let users revoke access for their Google Account, and then log in and grant access to a different account.
If you use removeCacheAuthToken, then authorize again, and see no popup, then that means the extension still has access to certain APIs. To check which apps have been granted access to which Google services, go to permission settings and have a look.
There are several ways to revoke access:
Go to chrome://identity-internals/ and remove the tokens that you want. Then click on the Authorize button, and you should see a popup to choose the Google accounts to grant access.
Of course, that method is for testing only. Your end users won't see the access token for your extension if they visit that page.
When the user clicks on the Revoke access button, or whatever name you call, display a popup that tells them to go to the permission settings page to manually revoke access.
Create a form on the current web page, add access token to the form and submits to the https://oauth2.googleapis.com/revoke endpoint.
From my experience, method 3 seems like an ideal solution, but it was a hit and mix for me. Sometimes I would get an invalid or expired token error, and troubleshooting it is not worth it. I would stick with method for peace of mind.
As mentioned in this answer, you can use https://accounts.google.com/o/oauth2/revoke?token=" + current_token) to allow the user to revoke access to the api.
Below is the function for the same:
function revokeToken() {
user_info_div.innerHTML = "";
chrome.identity.getAuthToken({ interactive: false },
function (current_token) {
if (!chrome.runtime.lastError) {
// #corecode_begin removeAndRevokeAuthToken
// #corecode_begin removeCachedAuthToken
// Remove the local cached token
chrome.identity.removeCachedAuthToken({token: current_token}, function(){});
// #corecode_end removeCachedAuthToken
// Make a request to revoke token in the server
var xhr = new XMLHttpRequest();
xhr.open(
"GET",
"https://accounts.google.com/o/oauth2/revoke?token=" + current_token);
xhr.send();
// #corecode_end removeAndRevokeAuthToken
// Update the user interface accordingly
changeState(STATE_START);
sampleSupport.log("Token revoked and removed from cache. " +
"Check chrome://identity-internals to confirm.");
}
});
}
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'm trying to write the password reset part of my authentication app. I chose to use JWT, node.js and express where I use the following logic: first, the user enters their email and a token is generated and sent to the user's mail in a password reset link. second, when the user presses the link a function is set to check if the token is correct and if it's still valid and third i have a function to save the new password to the database.
What I'm uncertain about is the second step where the token is supposed to be checked. Some tutorials say that you're supposed to save the token to your database and then compare the token in the link to the token in the database. But isn't the point with using JWT to not save anything to the database as reference? Shouldn't I just use jwt.verify to get the information saved in the token and then check for the user in the database and if it's still active?
Is this the correct way of using JWT? Or would you recommend me to use session instead of JWT?
There's a good suggestion in this answer. You can use some hash of your currently stored password value as part of the password reset JWT.
So the payload might contain { sub: user_id, exp: "now + 10 minutes", purpose: "password_reset", key: hash(hashed_password_from_db).substr(0, 6) }. This token can only be used successfully once.
There is a simple flaw in the use of JWT for reset password implementation.
From your current implementation, A user can generate the reset password link multiple times. So a user can have many active reset token in a given time.
Yes, JWT statelessness can be adopted, but it is not efficient in this case as you can have multiple tokens which can be used to reset the password even after the user has reset the password(depending on your approach).
I work in an organisation where testing and security is paramount. Your implementation would not be allowed.
The rule is that only one reset password link can be active at a time.
So JWT token is not the best option for us.
So what I do is to generate a random token saved in the DB(also with the current time). This token is to identify the user and, the time is to validate that the user is resetting withing a given time.
While the token is active, if a user decides to generate the token again, the former token is made inactive before a new one is generated.
The advantage of this method is that you can only have one active token at a time.
Lastly, JWT should be used if you don't mind a user having multiple active tokens/links at a time.
My webapp allows different users to login in different tabs/browsers on the same machine with different credentials (using signInWithEmailAndPassword). I achieve this by calling firebase.initializeApp(config, 'appName'+new Date().getTime()) for each login
When the user closes the tab or reloads (in window.onbeforeunload) I call .auth().signOut() to log him out.
I now want to add a RemeberMe functionality to my app page, that is a tickbox that if (and only if) ticked, will allow following logins from the same machine and username without giving the password even if the machine was for example restarted in the meantime.
How can that be achieved ?
what I am thinking about is (when remember me is on) to generate a token on the client stored in a cookie and maintain a table on the db which links tokens to passwords, there are two problems with this, first of all the password is saved as is on the db which is bad and second the password needs to be sent back to the client which is also bad.
any better options ?
Starting with Firebase JS 4.2.0 you can now specify session persistence. You can login different users in multiple tabs by calling:
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION)
And when the window is closed, the session is cleared.
For more on this, check https://firebase.google.com/support/release-notes/js#4.2.0 and https://firebase.google.com/docs/auth/web/auth-state-persistence
Just add a rememberMe checkbox to your login form with a reference variable(for an exmaple remember) and use firebase setPersistence like this,
firebase.auth().setPersistence(this.remember.checked ? fireauth.Auth.Persistence.LOCAL : fireauth.Auth.Persistence.SESSION)
(here I have used javaScript for the example)