I have a single-page JavaScript application and I'm using the Auth0 service for signup/login.
I have integrated the Lock widget and I'm saving a string to localStorage after a user is authenticated, like so:
lock.on("authenticated", function(authResult)
{
localStorage.setItem('login', authResult.idToken);
}
The problem is that when Auth0 redirects them back to my application after logging in, the authenticated event is fired only after page loaded, but by that time, I've already done the check to see if the localStorage string is set (which it is not); therefore, the user just keeps getting asked to login again:
if(localStorage.getItem('login') == undefined)
{
lock.show(function(err, profile, token)
{
// ...
}
}
I tried to see if there was anything special passed in to the page after a callback - but the referrer isn't always there.
If I don't automatically prompt the user to login, but instead show a login button - the authenticated event never fires for some reason.
How do I get around this?
Based on the information provided you seem to be using Lock in redirect mode and if that's the case you can use the hash_parsed event as a way to know if Lock found a response that it will process.
Every time a new Auth0Lock object is initialized in redirect mode (the default), it will attempt to parse the hash part of the URL, looking for the result of a login attempt. After that, this event will be emitted with null if it couldn't find anything in the hash. It will be emitted with the same argument as the authenticated event after a successful login or with the same argument as authorization_error if something went wrong.
Leveraging this event you could do the following:
Subscribe to the hash_parsed event:
If hash_parsed is emitted with null and localStorage has no indication the user already logged in then redirect to login.
If hash_parsed is emitted with a non-null value that either the authenticated or authorization_error will be emitted and you can react accordingly.
Some sample code:
lock.on("hash_parsed", function (response) {
if (!response && !localStorage.getItem('login')) {
// Redirect to the login screen
} else {
// Either the user is already logged in or an authentication
// response will be processed by Lock so don't trigger
// an automatic redirect to login screen
}
});
Related
I'm currently using Workbox to get some caching done with Service Workers. Right now, I'm facing the issue of removing more personalised data from the cache when the user logs out. We have already implemented this by posting a message to the SW upon the logout action. However, I'm having trouble handling the edge case where the user deletes the cookies. Because of how we do authentication, the user is logged out upon cookie deletion. But we are unable to detect this deletion and thus unable to clear the cache.
Any suggestions on how to handle edge case or to better handle authenticated assets in SW/Workbox? Thanks!
Below is a short example of our current flow.
* sw.js */
self.addEventListener("message", msg => {
if (msg.type) {
switch (msg.event) {
case "LOGOUT":
// delete caches which contain personalized data
Promise.all(
exprPlugins.map(plugin =>
plugin.deleteCacheAndMetadata(),
),
)
// ... other code
break;
}
}
});
You might be thinking this in a too SW specific way I guess :-)
Pseudocode:
// Page loads / timer fires every one minute
// if (no cookie found)
// -- send logout msg to sw
// else
// -- send "the user logged in is *id from cookie*" kinda event
// -- sw checks the data matches whoever is now logged in and if needed purges the cache
Please note that since this is not an automatic event after the cookie is manually deleted, an ill-meaning user could open Dev Tools and look at the data from the previous user. Thus this is NOT SECURE, it's more like a tongue-in-the-cheek workaround.
As others pointed out, you should probably not be caching any critical PII info into the caches.
I'm using the Google Identity Platform's OAuth 2.0 flow to authorize a javascript/HTML teacher observation form to write to a Google Sheets document. Everything is working well most of the time; however, last night one of our principals hit the following error:
"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project."
I determined that he had launched the observation tool in the afternoon, and now maybe five hours later was trying to click the submit button. My hunch was that the token had expired, but from Google's documentation it seems like the JS auth library is meant to handle refreshing the access token as necessary - I believe it's not actually possible to get a refresh token to do anything manually.
I'm using what is essentially the sample auth code, and the app responds to being signed out appropriately. That is, if I sign out in another tab, the submit button is disabled and the sign-in button appears again. Assuming token expiration is the issue here, any ideas on the correct way to identify if the token has expired and how to request a new one, ideally without user interaction? Or if it's not an expiration issue, what else could it be? This user has successfully submitted data in earlier observations; it was just this one time when he waited ~5 hours (potentially losing internet connectivity / sleeping his laptop) during that time.
Here's the auth code:
var clientId = ""; //id removed
var discoveryDocs = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
var scopes = "https://www.googleapis.com/auth/spreadsheets";
var authorizeButton = document.getElementById('authorize-button');
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
function initClient() {
gapi.client.init({
discoveryDocs: discoveryDocs,
clientId: clientId,
scope: scopes
}).then(function () {
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
});
}
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
authorizeButton.style.display = 'none';
document.getElementById('submit').disabled = false;
findRow(); //find the empty row once we're logged in
} else {
authorizeButton.style.display = 'block';
document.getElementById('submit').disabled = true;
}
}
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
}
Thank you!
Similar issues that i had resulted in issues from that Authorized Javascript origins.
"In the Authorized JavaScript origins field, enter the origin for your app. You can enter multiple origins to allow for your app to run on different protocols, domains, or subdomains. You cannot use wildcards. In the example below, the second URL could be a production URL." taken from https://developers.google.com/identity/sign-in/web/devconsole-project.If prompt to view task came from an email, the email origin must be verified -or- the device is used for multiple accounts, the token will not stay. If the api is being improperly used, it will allow functionality for a short period of time , then fail.
This may be useful, in the authflow, you do not have scope or id in options
/** * Initiate auth flow in response to user clicking authorize button. * *
#param {Event} event Button click event. */ function
handleAuthClick(event) {
gapi.auth.authorize( {client_id: '[#app:client_id]', scope:
["googleapis.com/auth/calendar"], immediate: false}, handleAuthResult);
return false; }
I believe How to refresh expired google sign-in logins? had the answer I needed. Since all of my API calls happen at once, I added a new Date() when the page loads, a second new Date() when the submission flow begins, and if they are more than 45min (2,700,700ms) apart, I use gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse() to force an access token refresh, as documented at https://developers.google.com/identity/sign-in/web/reference#googleuserreloadauthresponse.
Hopefully Google will eventually update their documentation to reflect this now-necessary step when using the auth2 flow vs the older auth flow.
Time will tell if this actually solved the issue, but I'm hopeful!
I hope it helps you friend that error is because you have the wrong time, you go to date and time settings then press synchronize now.
I've implement Firebase Authorization to login on my iOS app via Facebook and Google. I'm coding Swift.
When the app starts up I need to check whether a user is already signed-in in order to present the proper ViewController (e.g., if nobody is signed in I present the Login View Controller, otherwise I present the Home View Controller).
If I use the "easy" solution offered by Firebase, meaning
if FIRAuth.auth()?.currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
So checking if the current user is not nil, it happens exactly what the Firebase guide (https://firebase.google.com/docs/auth/ios/manage-users) alerts might happen meaning
"Note: currentUser might also be nil because the auth object has not finished initializing. If you use a listener to keep track of the user's sign-in status, you don't need to handle this case."
So I would like to implement the listener as suggested in the guide:
handle = FIRAuth.auth()?.addStateDidChangeListener() { (auth, user) in
// ...
}
The listener will handle also intermediate status so that it is triggered when the Auth object is created. Point is I really cannot make it to work properly. Anybody can help me to use this listener in order to check if a user is logged in?
Thanks
I've implemented it like this:
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if let user = user {
// User is signed in. Show home screen
} else {
// No User is signed in. Show user the login screen
}
}
If you don't need the User object after checking, you can replace if let user = user with a boolean test, like this:
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if user != nil {
// User is signed in. Show home screen
} else {
// No User is signed in. Show user the login screen
}
}
Where to put the listener (from the comments):
For the cases I used to check if a user is signed in, it was enough to put it at the beginning of viewDidLoad in the specific view controller. But if you have any cases where you need to check every time you enter the specific view controller then it would be better to put it at the beginning of viewDidAppear. But I think in most cases you need to check only once, if the user enters the view
If you're setting up the StateDidChangeListener in application:didFinishLaunchingWithOptions, you'll notice that it fires once when the listener is attached (to set the initial state, which is nil when initialising) and then again once it's finished initialising (potentially not nil). This is intended behaviour, but really impractical if you're setting it up early.
An alternative to using the listener is using NotificationCenter. This will fire once initialisation has finished:
NotificationCenter.default.addObserver(forName: NSNotification.Name.AuthStateDidChange, object: Auth.auth(), queue: nil) { _ in
let user = Auth.auth().currentUser
}
I've managed to successfully log in FB using FB.Login function. Now I want to log out:
FB.Logout();
Debug.Log("FB IS LOGGED IN " + FB.IsLoggedIn);
I am expecting the above code to print the value of FB.IsLoggedIn as false and to ask me for a login and password on the next FB.Login.
In fact the value of FB.IsLoggedIn is true and I am not being logged out: next call to FB.Login does not ask for password and I am not being logged out when I open facebook site in my browser.
I've also tried to use the undocumented request to https://www.facebook.com/logout.php?next=[YourAppURL]&access_token=[ValidAccessToken] but it didn't make any effect for me.
How can I log the user out of facebook in my standalone unity application?
In fact what I need is to log in with different login and password.
Maybe I can invalidate the access token somehow which will cause the FB to ask me for login and password again?
Any help is much appreciated.
SDK version: 5.0.1
Build version: 140401.725cc2ecbc9002a
Unity Version 4.3.3f1 (c8ca9b6b9936)
I believe the FB.Logout operation is asynchronous, and the value of FB.IsLoggedIn would be true immediately after calling FB.Logout(). If you look at the documentation, it says:
You almost certainly should not use this function, which is provided
primarily for completeness. Having a logout control inside a game that
executes a Facebook-wide logout will violate users' expectations.
Instead, allow users to control their logged-in status on Facebook
itself.
Actually FB.Logout() has no delegate to let you know that account is successfully logout, so you have to create your own listner.
Secondly it will not sign you out from the actual device Facebook app or browser.
If you want to sign in with different account, so you can do by signing out explicitly from the app or browser.
Here is the code for how to detect that if you are logged out. It may useful to show Login and Logout button for Facebook that when to Login or Logout.
Here is the code from that you can determine the user has logged out within the Game.
public void OnFacebookLogout()
{
if (FB.IsLoggedIn)
{
FB.Logout ();
StartCoroutine ("CheckForSuccussfulLogout");
}
}
IEnumerator CheckForSuccussfulLogout()
{
if (FB.IsLoggedIn)
{
yield return new WaitForSeconds (0.1f);
StartCoroutine ("CheckForSuccussfulLogout");
} else
{
// Here you have successfully logged out.
// Do whatever you want as I do, I just enabled Login Button and Disabled
// logout button through this method.
EnableFacebookLoginButton ();
}
}
I'm not sure if it is correct but why not just do some while loop?
IEnumerator FBLogout (){
FB.Logout ();
while (FB.IsLoggedIn){
print ("Logging Out");
yield return null;
}
print ("Logout Successful");
}
I have a set of links (add to wishlist) with click event . The click event checks if the user is logged in (ajax request) and depending on the result the click continues. In the case the user is not logged in I have a generic jQuery UI modal dialog that the user can use to log in.
That all works well but I would like to extend the functionality to be able to continue with click of the links after the user logs in using the dialog.
ie. CLICK ADD TO WISHLIST -> LOGGED IN ?
YES -> CONTINUE LINK CLICK (add to wishlist)
NO -> SHOW LOGIN DIALOG ->
USER SUBMITS CREDENTIALS -> LOGGED IN?
YES => CONTINUE LINK CLICK (add to
wishlist)
NO => SHOW LOGIN ERROR
Of course I do not want to perform any postbacks, all through ajax and jquery.
Thanks
You could pass the url of the click action to the login modal and redirect after successful login.
Alternativly, if you have set it up to login via AJAX, you could store the click event target and then trigger a click event after a successful login.
Something like the following:
var is_logged_in = false;
$('a.add_to_wishlist').click(function(e) {
if(is_logged_in) {
//do stuff
} else {
show_modal(e.target); //pass the event target to the modal
}
});
function show_modal(trigger) {
//do stuff
is_logged_in = true;
$(trigger).trigger('click');
}
Hopefully this helps.
If you're in control of your server side code then you should place the authentication + save to wish list in the same request.
User clicks add to wish list
Ajax request to add page to wish list is sent to server.
Server check to see if user is logged in.
If the user is logged in: save the item to the wish list and return a success response.
If the user it not logged in: return a failed response.
The ajax response callback should update the UI based on the response.
If you're not in control of your server code then you'll have to make two ajax request if the authentication request is successful.