We have some web application that allows users login and do some work.
But sometimes users work with our web site opening more then one browser and this causes us a lot of problems.
How could we implement the following - on user log in to our web site, make automatic log out in all his previously logged in browsers?
Thanks a lot.
You can use JS localStorage on page load to detect a user login, the event will be fired on every tabs or window opened within the same domain :
function storageChange(event) {
if(event.key == 'user_login') {
// logout - except current window
}
}
window.addEventListener('storage', storageChange, false);
//when user logs in
window.localStorage.setItem('user_login', true);
That will work only if the user is using the same browser multiple times.
Related
I have a custom button which is to query and possibly update an Administration App in Quickbase, which the current user doesn't require access to.
I have JS code which is executed on a button click by the user to check the admin app, etc...
my API call to check the app has the appropriate apptoken and usertoken. However, the browser still has the current user's session cached, so the API call errors out with an access denied error message.
I'm looking for either a way to make a hidden incognito window, to then execute this code, or a way to problematically force the usertoken to supersede the current user access/permissions.
I've seen where chrome extensions can use chrome.windows.create... but I have no experience with extensions, and Ideally, I don't want to have to have an extension for just this functionality, and have to possibly install it on every user's PC for this to work...
Here is a snippet of my current code... This code does work if someone has permissions to the Administration App... but this code is residing in a different application:
PreProcURL = "https://<domain>.quickbase.com/db/<dbid>?a=API_DoQuery&apptoken=<>&usertoken=<>&query={'3'.EX.'1'}";
PreProcQuery.open('GET', PreProcURL, 'async');
PreProcQuery.send();
PreProcQuery.onload = function(){
console.log(PreProcQuery.responseXML);
RunBit = (PreProcQuery.responseXML.documentElement.getElementsByTagName("runbit"))[0].innerHTML;
SupportData = (PreProcQuery.responseXML.documentElement.getElementsByTagName("supportdata"))[0].innerHTML;
if(RunBit != "1"){
$.get("https://<domain>.quickbase.com/db/<dbid>?a=API_EditRecord&rid=1&_fid_6=1&_fid_7="+rid+"&apptoken=<>&usertoken=<>");
}else{
if(SupportData == rid){
alert("This PreProc File is already in progress... please wait.");
}else{
alert("Another PreProc is already in progress... please wait.");
}
}
};
Thanks in advance for any assistance on this.
API calls executed in JavaScript that is hosted within quickbase.com (button, pages, etc.) will run as that logged in user that triggered the script. The usertoken gets ignored.
The most common way to accomplish what you are after is to write the API_DoQuery code on a server side location and then trigger it from your JS code.
I'm currently working on making my code compatible with Safari ITP 2.0. In a method that is triggered on an onClick, I have code similar to the code below:
if (document.hasStorageAccess && document.requestStorageAccess) {
console.log('On Safari 12');
document.hasStorageAccess().then(
function successful(hasAccess) {
console.log('Testing if hasAccess');
if (hasAccess) {
console.log('Access granted already');
} else {
console.log('Requesting access');
document.requestStorageAccess().then(
function successful() {
console.log('Access request was a success');
window.location.reload();
},
function fail() {
console.log('Storage Access API call failed...');
});
}
},
function rejected(reason) {
console.log('hasStorageAccess failed: ', reason);
});
}
However, running this gets me the logging statement "'Storage Access API call failed...'" without a prompt from Safari - what's more frustrating is that it previously worked but is now starting to fail again. Is there any way to debug why the call to requestStorageAccess failed?
I tried enabling the ITP debug mode logs as per the instructions, and I did get some use out of that. It gave me this error once:
2018-09-04 15:15:40.930157-0700 0x110c87 Info 0x0
69100 Safari Technology Preview: (WebKit)
[com.apple.WebKit:ResourceLoadStatisticsDebug] Cannot grant storage
access to example.com since its cookies are blocked in third-party
contexts and it has not received user interaction as first-party.
But when I accessed it in a first party context and reloaded the page, I got no further reasons why the call to requestStorageAccess was failing. If anyone has any ideas, please let me know what you suggest I try to debug the issue.
Thank you!
There are updated debug instructions: https://stackoverflow.com/a/61532464/13443904
But I also wanted to provide some more concrete steps for people struggling with Safari ITP, since it took ages to figure out all the rules.
1) Don't embed requestStorageAccess inside hasStorageAccess. This loses the required user interaction (button click) needed to prompt for requestStorageAccess.
2) hasStorageAccess and requestStorageAccess are promises. Make sure any follow-up actions are nested -inside- the success closures of the promise (ie, if you have a submit button, don't let it submit the form before you've finished asking for requestStorageAccess).
3) You have to set a 1st party cookie and have a user interaction from a top-level window for your subdomain BEFORE you can requestStorageAccess for a 3rd party cookie via user interaction in an iframe for your subdomain. Setting a cookie/interaction in the main domain/parent window does not count.
4) Testing in Safari Technology Preview makes resetting the ITP choices easier - just clear history and quit/reopen and you should go back to scratch. Safari seems to cling to the values forever.
Did you interact (tap/click/form entry) with your website as first party? A mere visit does not suffice. The user has to interact with a webpage with the same eTLD+1 as the domain that is requesting storage access.
Example:
1) service.example is classified with tracking abilities by ITP.
2) The user visits and interacts with a page from service.example or *.service.example.
3) service.example calls the Storage Access API under othersite.example when the user taps in service.example’s iframe.
On my Django site, I want to logout from the site automatically when I close the tab or browser. I mean when I close the site by closing the tab instead of using logout button, after entering the URL again, I want to see that the user has already logged out from the site to force the user to enter username and password again.
Is there a way to handle closing the tab in JQuery?
Thank you in advance.
Edit: onunload & onbeforeunload events cause to logout the user when also reloading the page.
Add your logout code to the on onunload event.
window.onunload = function () {
//logout code here...
}
In JQuery you can use the .unload() function. Remember that you don't have much time so you may send the Ajax request but the result may not reach the client.
Another trick is to open a small new window and handle the logout there.
window.open("logout url","log out","height=10,width=10,location=no,menubar=no,status=no,titlebar=no,toolbar=no",true);
If you want to disable closing the window (or at least warn the user), you can use this code:
window.onbeforeunload = function(event) {
//if you return anything but null, it will warn the user.
//optionally you can return a string which most browsers show to the user as the warning message.
return true;
}
Another trick is to keep pinging the client every few seconds. If no reply comes back, assume the user has closed the window, browser has crashed or there is a network issue that ended the chat session anyway. On the client side, if you don't receive this ping package, you can assume that network connection or server has a problem and you can show the logout warning (and optionally let the user login again).
You can use Javascript onunload & onbeforeunload events. In these events destroy the session cookie for Django.
Those events are also fired when you leave a site over a link or your browsers back button so be careful and think twice if this is really what you want.
I just ran into this. In your Django settings.py file, you can add the flag:
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
This will log the user out when the browser is closed. Note that the user will remain logged in if there are other tabs or windows still open (the browser must be completely closed).
window.onunload = function () {
//logout code here...
window.open("logout url","log out","height=10,width=10,location=no,menubar=no,status=no,titlebar=no,toolbar=no",true);
}
This code works.
this will open a small pop up window for the logout url.
I've been researching this issue for quite some time now and have had no success. Hoping someone can shed some light on this!
I'm working on an Google Chrome Extension (browser action) where authentication/authorization is being done outside of Google (chrome.identity.launchwebauthflow with interactive set to true). We've had success with the authentication/authorization flow for some users but not all. Here are the interesting results:
User A clicks extension icon, clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
User B clicks extension icon, clicks Authorize button, extension pop up closes. It fails prior to exchanging auth code for access tokens.
User B right clicks on extension icon, selects Inspect popup, clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
User A starts up device in Safe mode with networking. User A clicks extension icon, clicks Authorize button, extension pop up closes. It fails prior to exchanging auth code for access tokens.
User A starts up device in Safe mode with networking. User A opens up a tab and loads the extension's url (chrome-extension://pathofextension). User clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
Extension is converted to a packaged app. User A and B opens app, clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
We think it's a client issue, but we're all using the same Chrome versions. What would cause the extension's pop up window to close when the auth code is being returned? We can't keep the developer console open to see if any errors appear because when the developer console is open it works just fine. We are using $.ajaxSetup({ cache:false }) to make sure caching is disabled for ajax requests.
Here's a snippet of the chrome.identity.launchwebauthflow call (originally called from the popup):
chrome.identity.launchWebAuthFlow({url:url,interactive:true},function(response) {
console.log('OAuth Response: '+response);
if (response) {
var authCode = encodeURIComponent(response.substring(response.indexOf('=')+1));
console.log('Auth Code: '+authCode);
userAuthorization(authCode);
} else {
authorizeButton();
}
});
Edited code after trying to apply the code-in-background solution:
Pop up script now calls background script:
chrome.runtime.sendMessage({type:'authorize',url:url},function(response) {
console.log(chrome.runtime.lastError);
console.log(response);
if (response && response.authCode) {
userAuthorization(response.authCode);
} else {
authorizeButton();
}
});
Background script responds to pop up script.
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse) {
if (message.type == 'authorize') {
var url = message.url,
authCode;
chrome.identity.launchWebAuthFlow({url:url,interactive:true},function(response) {
console.log('OAuth Response: '+response);
if (response) {
authCode = encodeURIComponent(response.substring(response.indexOf('=')+1));
console.log('Auth Code: '+authCode);
}
sendResponse({authCode:authCode});
});
}
return true;
});
Invoking launchWebAuthFlow from an extension popup is a very bad idea.
This operation is supposed to create a new window and focus on it. By Chrome UI conventions, this should close the extension popup - and with it, completely destroy the JavaScript context of that page. There will no longer be any callback to call.
This explains why "Inspect popup" helps - this prevents closing the popup on focus loss. There is no override for this mechanism outside of this debugging case.
This popup-dismissal behavior may subtly differ by OS, hence you might not have seen it on your development machine. But the convention is clear - any loss of focus should destroy the popup page.
The only truly persistent part of your extension that cannot be accidentally closed is the background script - that's where you should handle the chrome.identity authorization. Send a message from your popup code that requests it.
Update: Note that you can't return a response to sendMessage for the same reason - the popup no longer exists. Your logic should be to try to retrieve the token with interactive: false every time the popup opens - and if that fails, request the background to initiate the interactive flow (and expect to be closed, so no sendResponse).
My application uses oauth to allow a user to login to Salesforce, and after logging in, they can access the application. What currently happens is:
The user clicks the "login" link, and is redirected to Salesforce
The user logs into Salesforce, and is redirected to the URL I specified
My server processes the request and redirects them to the home page
What I would like to do is this:
The user clicks on the "login" link, and a new window (window.open) with the Salesforce login page appears
The user logs in, and is redirected to the URL I specified
Once the server redirects to the home page, the home page fires a success or logged_in event in the window, which the original page listens for and interprets
This is what I've made so far (assume there is <button id="login">Log in</button>)
$('button#login').on('click', function() {
var popup = window.open('/auth/salesforce', 'login', '...');
popup.addEventListener('success', function() {
popup.close();
alert('Logged in');
});
});
and in the home page, I added to the section that displays when a user is logged in successfully:
var event = window.createEvent('loginSuccess');
event.initEvent('success', true, true);
window.dispatchEvent(event);
However, the success event is never fired. How would I fire a success event in the home page, to alert the original page that the user is successfully logged in?
Edit: I noticed there is the window.postMessage method, as referenced in the MDN docs. Is this what I should use? Or should I use another method to capture a successful login event on the newly created window?
I recently just put the same OAuth in our application. Don't try to use a new window to auth users just like all the social networks just let the page that the user is on go to the auth screen and then redirect you back... The only other way this can be done (and i'm not sure salesforce has this yet) is a javascript auth process.
Through my research, I found that the best way to accomplish this, at least if I don't need to support IE browsers, is to look at the window.opener value, and if it exists, run a function defined in window.opener. For example,
if (window.opener) {
window.opener.userIsLoggedIn();
}
window.close();
userIsLoggedIn() would be defined in the parent window that opened the new pop-up.
With that said, a couple caveats: in certain IE environments, window.opener will lose its value due to some security restrictions, thus making window.opener null and never firing the userIsLoggedIn() method on the parent window. In these cases, I would listen for the close event on the created window, and if the userIsLoggedIn() function hasn't fired, refresh the page. A second caveat is that you will only be able to call window.opener.userIsLoggedIn() if and only if it matches the Same Origin Policy; see the Wikipedia article on the subject. If this poses an issue and you cannot work your application around these restrictions, see this project for possible workarounds/hacks.
I don't have a need to support IE so I have not created this code, but if the window.onclose method fires in IE, listen for the window.onclose event and perform your checks after this happens.