1

In my Angular app i've implemented e-mail confirmation, so when a new user account is created, a confirmation e-mail will be sent to the registered e-mail address.

The user can log in unconfirmed, but they have access to limited functionality of the app until they visit the link in the confirmation e-mail (the confirmation link opens the application in a separate tab).

The relevant part of my AuthService looks like this:

private readonly KEY_AUTH = '_auth';

private currentAuthSubject = new BehaviorSubject<Auth>(
  JSON.parse(localStorage.getItem(this.KEY_AUTH)));

// My Components subscribe to this Observable to get notified on Auth changes
public currentAuth = this.currentAuthSubject.asObservable();

// This function is used to set the authentication object on login
// (or delete it on logout by calling setAuth(null))
setAuth(auth: Auth) {
  if (auth) {
    localStorage.setItem(this.KEY_AUTH, JSON.stringify(auth));
  } else { localStorage.removeItem(this.KEY_AUTH); }
  this.currentAuthSubject.next(auth);
}

// This function is called when the user is already logged in and being confirmed
// (by clicking the confirmation link)
setAuthConfirmed() {
  const auth = this.currentAuthSubject.value;
  if (auth) {
    auth.confirmed = true;
    localStorage.setItem(this.KEY_AUTH, JSON.stringify(auth));
    this.currentAuthSubject.next(auth);
  }
}

The confirmation basically works fine, but i have the following problematic case:

  1. In tab A the unconfirmed user is logged in to the application (limited functionality).
  2. In tab B they open their e-mail and click on the confirmation link.
  3. The app opens in tab C, the confirmation happens and the user has full functionality.

And here comes the problem:

  1. In tab A the user still has the limited functionality, even when navigating between components that are subscribed to currentAuth.

    In this tab the confirmed field of the Auth object is still false.

    This can be resolved only by refreshing the page.

Is there a way to update the auth state in tab A without having to manually refresh the whole page?

I'd really appreciate any advice.

justanoob
  • 1,797
  • 11
  • 27
  • make a http request to the server to check if the email is confirmed or not every 2 seconds for example, or you can use the websocket so the server can notify the browser about the confirmation and it will be updated – Mohamed Kallel Aug 20 '19 at 14:20
  • 2
    Maybe with window.addEventListener('storage', function(e) { ... Your code there .. }); ? – Simrugh Aug 20 '19 at 14:25

5 Answers5

0

You could subscribe to localStorage changes:

window.addEventListener('storage', function(event){
    if (event.storageArea === localStorage) {
        // It's local storage
    }
}, false);

Another think you could do is to do an interval that checks if it changed on localStorage, if yes then you emit the new value.

  • I would avoid this as it is very taxing on the dom. Depending on your application this may be fine. But best practice dictates to avoid event listeners where possible. Angular is asynchronous and thus largely reduces the need to use event listeners. I understand they're necessary at times, but a simple login authorization should avoid the overhead of listening to events. Also, it is poor community etiquette to downvote everyone's answer that doesn't perfectly answer the question. These are mostly valid answers but all downvoted. Downvotes hurt our reputation and we're just trying to help you. – kenef Aug 20 '19 at 20:31
  • @kenef Just for the record, i didn't downvote anyone, someone else did. – justanoob Aug 21 '19 at 06:39
-1

make a http request to the server to check if the email is confirmed or not every 2 seconds for example by creating a new rest service in your server for email confirmation checking, or you can use the websocket so the server can notify the browser about the confirmation and it will be updated

-1

You can try do create an Interceptor which would check the currentAuth with every request and update it when possible and needed.

So in the tab A it'll updated with the first request after the update in the tab C

igor_c
  • 1,200
  • 1
  • 8
  • 20
-1

You can use localstorage for setting some kind of flag if user is authenticated or not. Subscribe to the localstorage event change Stackoverflow Question.

There is also a good article on this about sharing sessions between tabs Link

-1

Why don't you use ngOnInit() and ngAfterViewInit() to handle your tasks for tab C?

Call setAuthConfirmed() in ngOnInit (runs as soon as the request is received but before the view renders) and check the users authentication in ngAfterViewInit(). When I implement what you're trying to do, I use a global user class that has app-wide scope. So I can control logged-in vs non-logged in user displays and permissions with a boolean property. I set the values for the global user class in the login component. Then every component that is accessed thereafter checks the user class properties to decide how to deal with the user.

Lifecycle Hooks will probably get you what you're looking for: https://angular.io/guide/lifecycle-hooks

kenef
  • 183
  • 10