Angularjs: Why page refresh destroy the values of $rootScope? - javascript

In my local route http://localhost:9000/#/deviceDetail/ I have a controller that manage that view. Before going to that view I set some variables to the $rootScope (for example $rootScope.dashboards).
Once on that view I have acces to dashboards property, but when I refresh the page with F5 key for example the property dashboards is lost.
I tried to save the $rootScope on the localStorage variable but I got circular reference problems with the JSON.stringify method.
Any tip to manage that?

AngularJS is a JavaScript framework, everything is stored in memory heap and the heap is starts when you open a page and it's destroyed after you close it. In this context, browser refresh is like closing and re-opening the page.
To keep the value after refresh, you should store it in a cookie, for this you use for example $cookies or sessionStorage / localStorage as recommended by M K.

I tried to store auth token using cookies following the article at Getting started with AngularJS and ASP.NET MVC - The long awaited Part Three. But the cookies is destroyed whenever I hit F5 or refresh the Chrome browser.
That article says ngCookies helps to deal with page refresh to maintain token for page refresh. And I had thought it did and I did not know ngCookies killed me. It was destroyed if page is refresh! after hours to research online I see this article helps me.
According to M K, I used localStorage (or sessionStorage) helped me to get rid of the headache of cookies. Using cookies to store authentication token or something else is a bad idea. I ran into that problem and I got lost (did not know the bug coming from "using cookies") as the above article mentioned/confirmed. So, it was a bug in that article.
Thank you million times, M K.

Use localStorage and $stateChangerStart check if you using ui.route
something like this
$rootScope.$on('$stateChangeStart', function(event, toState) {
// Grab the user from local storage and parse it to an object
var user = JSON.parse(localStorage.getItem('user'));
if(user) {
$rootScope.currentUser = user;
}
});

Related

Google oauth session lost after page reload (javascript)

I recently moved from the deprecated gapi.auth2 to the new Google Identity Services, using the javascript client library, and noticed a big difference: if someone signs in, and then reloads the page, the session is lost, and has to sign in again, every time the page is loaded. This was not the case with the deprecated library.
The problem can be easily reproduced with the Calendar API example.
Is there any configuration option to keep the session persistent? Or do I need to store the access tokens somehow? I could not find anything relevant in the official docs.
UPDATE:
The migration guide states the following:
Previously, Google Sign-In helped you to manage user signed-in status using:
Callback handlers for Monitoring the user's session state.
Listeners for events and changes to signed-in status for a user's Google Account.
You are responsible for managing sign-in state and user sessions to your web app.
However there's absolutely no information on what needs to be done.
UPDATE 2
To be more specific, the actual issue is not making the session persistent. Managing the sign in state and user session is something I can solve.
The real problem is the access token used to call the Google APIs.
As mentioned in the comments, the access tokens are 1) short lived 2) are not stored anywhere, so even if not expired, they do not persist between page reloads.
Google provides the requestAccessToken method for this, however even if I specify prompt: '', it opens the sign-in popup. If I also specify the hint option with the signed in user's email address, than the popup opens, displays a loading animation briefly, and closes without user interaction. I could live with this, however this only works if triggered by a user interaction, otherwise the browser blocks the popup window, meaning that I cannot renew the token without user interaction, e.g. on page load. Any tips to solve this?
I faced all the same issues you described in your question.
In order to help:
Google 3P Authorization JavaScript Library: in this link we can check all the methods the new library has (it does not refresh token, etc..)
This doc says the library won't control the cookies to keep the state anymore.
Solution
Firstly I need to thanks #Sam O'Riil answer.
As Sam described: "you can somehow save access token and use it to speed-up things after page reload."
Given the the Google's exampe, we should call initTokenClient in order to configure the Google Auth and the requestAccessToken to popup the auth:
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
prompt: 'consent',
callback: tokenCallback
});
tokenClient.requestAccessToken({prompt: ''})
In your tokenCallback you can save the credentials you get somehow, e.g.:
const tokenCallback(credentials) => {
// save here the credentials using localStorage or cookies or whatever you want to.
}
Finally, when you restart/reload your application and you initialize the gapi.server again, you only need to get the credentials again and set token to gapi, like:
gapi.load('client', function() {
gapi.client.init({}).then(function() {
let credentials = // get your credentials from where you saved it
credentials = JSON.parse(credentials); // parse it if you got it as string
gapi.client.setToken(credentials);
... continue you app ...
}).catch(function(err) {
// do catch...
});
});
Doing it, your application will work after the reload. I know it could not be the best solution, but seeing what you have and the library offers, I think that's you can do.
p.s.: the token expires after 1 hour and there is no refresh token (using the implicit flow) so, you will have to ask the user to sign-in again.

AngularJS - How to make a token inaccessible from console or malicious attacks?

I'd like to store a token on the client but am worried about malicious attacks on the clients browser.
What's the best way to store this variable during the session?
Here is my implication so far:
Create an isolated scope in the 'HeadersInterceptor' function so only that function can access it.
What's the best way to store this variable on client storage?
Here is my implication so far:
Localstorage...
I do feel like I'm going in the right direction here, but I'm stumped on storing this variable for the client. Any insights would greatly be appreciated!
You can't.
Anything that's accessible from your JS app is accessible from the developer console too, that's just the nature of client-side scripting.
Hiding it in a private variable or a service, as other answers suggest, are nothing more than obfuscation - it'll make it more of a nuisance to get, but it's there and available nonetheless.
Even if you find a method which makes it directly inaccessible from the developer console, per se, a malicious user will still be able to just modify the JS files themselves - it's a losing battle.
My thoughts on this:
What's the best way to store this variable during the session?
sessionStorage
What's the best way to store this variable on client storage?
sessionStorage
But if you don't want it accessible at all, even from the console (sessionStorage and localStorage are accessible from the console), I would think you should forgo storing it in LS and simply hold a reference in memory. Keep the token wrapped in privately in a closure and access it via a service. Like so:
app.factory('tokenSvc', function(){
var token;
return {
setToken: function(_token) {
token = _token;
},
getToken: function() {
return token;
}
};
});
Because Angular is a SPA framework, that token reference will persist as long as your application is active. So maybe you would set the token in your $http interceptor function, and then access it as need via getToken.

Facebook User Feed Subscriptions

I have what I'm sure will be a very easy question, I'm just confused.
I have successfully got my server subscribed, for real time user/feed but simply am not getting any updates.
I have logged myself in using the FB.login JavaScript SDK, using the scope "user_about_me,user_status,read_stream" - so I expected to see updates for my user, but not getting anything at all.
The app is in "Development Mode", so, can anyone confirm that since I have got a { success: true }, that the reason is simply because of this? Or perhaps I need to put it under review from Facebook?
Thanks.
Woo, it's fixed now!
On my research, I had come across this post:
How to subscribe to real-time updates for a Facebook page's wall
Not realizing that I can use the USER_ID in place of the PAGE_ID. Following the Real Time Subscription documentation, I thought that by using the APP_ID, that it would allow to make one subscription for all users that grant the application its scope.
On to the next hurdle...

Does ngStorage perform operations asynchronously?

I'm working with angular.js and ngstore. I'm using a token based authentication with a node.js REST service, from the angular app I send my credentials to rest server and I receive the token, I then store this token in $localStorage to use throughout all the angular app($localStorage.token). But it turns that sometimes $localStorage.token is undefined, even when I assigned the token to it, so when I call another rest endpoint sending the token in the headers, I'm actually sending an undefined value. Also when I try to logout I do
delete $localStorage.token
but when I check if the user has been loggedout actually the token still there.
What is strange is that if I set breakpoints right after deleting the token or assigning the token and wait for a while, everything works, that's making me think that those operations may be asynchronous?
Is this a common problem? How could I fix this?
Any help would appreciated, Thanks.
EDIT: actually I found that the problem is when using window.location, if I use $location.path it's working, but for certain reasons I need to use window.location, and it should work as far as I know
I had the same problem today, and using the following commit worked for me.
https://github.com/raynode/ngStorage
There is a helpful discussion about this problem here:
https://github.com/gsklee/ngStorage/issues/39
In this version of ngStorage, the author has thoughtfully provided a way to "save" before proceeding and performing a $window.location.reload();
During login:
$localStorage.value = 100;
$localStorage.$save();
(and then)
$window.location.reload();
During logout:
delete $localStorage.value;
$localStorage.$save();
$window.location.reload();
This worked for me to ensure that the $localStorage variables were deleted before page reload.
No, local storage is not asynchronous.
JavaScript is a single thread environment and read/write operations to local storage occurs immediately.
Both session and local storage containers are the same. Except that session storage is a key/value pair with an expire timestamp specified.
Storage in HTML5 is not a reliable resource. As there are a number of browser states that will restrict or remove storage.
You are referring to ngStore which is a module I've never heard of. There is no local storage module that is included with AngularJS by default, and there are multiple open source modules that handle this.
What is most likely happening is that you are handling a session token as a state variable instead of a state promise. When you use a variable to hold the state of a resource on the server, then that state has 3 possible values. 1 not assigned, 2 pending assignment and 3 value assigned.
Instead of reading the token from storage directly. You should have a service that returns a promise that will resolve to provide that token. This promise will only resolve after the REST operation has completed.

How can I get a Session in Meteor to display in a separate window?

I'm a Meteor newbie. In my client.js file I have:
if(Meteor.isClient) {
Template.infooutput.output = function() {
return Session.get("info"); }
I have a template:
<template name="infooutput">
{{output}}
</template>
and then in my main page
<body>
{{>infooutput}}
</body>
Now through console, if I set the Session.set("info", "hello")
I see on the screen, "hello". So that works fine however if I open another browser tab, with the same page open, I don't see the "hello". Is this update functionality only possible with use of a collection? Also, I'm a little confused about the purpose of a Session. Can you tell me why it might be used? Am I able to have current session updates shown in multiple browsers (other users viewing) without saving to my collection db?
If so, how might I do it?
Session data are isolated to the current browser instance (including tabs) - so opening a new tab will give you a clean state. Session variables are designed to be a programmer-controlled means to create reactivity on an individual client. They are one of several reactive data sources which can trigger client UI updates.
Meteor is designed to sync data with the client via collections, however there are other techniques that have been developed by community members. Most notably streams.
It's also worth noting, that the server can publish documents to the client which are not necessarily represented in the database. Please see this answer for more details.

Categories

Resources