4

I'm using a RxJs Subject authListener to get user auth status:

export class AuthService {
  private authListener = new Subject<boolean>();
  
  isLoggedIn() { return this.authListener.asObservable(); }
  
  login() {
    localStorage.setItem('token', token);
    ...
    this.authListener.next(true);
  }
  
  logoff() {
    localStorage.removeItem('token');
    ...
    this.authListener.next(false);
  }
}

So i'm able to call authListener value in components:

export class HeaderComponent implements OnInit {

  isAuthenticated = false;
  auth$: Subscription;

  constructor(private authService: AuthService) { }

  ngOnInit() {
      this.auth$ = this.authService.isLoggedIn().subscribe(
        (isAuth: boolean) => {
          this.isAuthenticated = isAuth;
        });
  }
}

However it doesn't seem reliable because the user could do something like refreshing the page, and then authListener would be lost. Is there a reliable way to do it? I'm trying to avoid localStorage because user could change authListener anytime.

UPDATE: It seems storing cookies is the way to go. How could I store Auth State and JWT Token inside a cookie using Node.js + Express (HttpOnly; Secure)? It should be something like this...

// login original response

res.status(200).json({success: true, token: token, reftoken: refreshToken, expiresIn: 900, name: user.name});

// login cookie response

res.cookie('token', token, { secure: true, httpOnly: true }); res.cookie('tokenref', refreshToken, { secure: true, httpOnly: true }); res.cookie('expiration', expireDate, { secure: true, httpOnly: true }); res.status(200).json({success: true, name: user.name});

James
  • 1,189
  • 2
  • 17
  • 32
  • What about using `sessionStorage`? And whenever the `authListener` changes, just clear the stored value – user184994 Oct 05 '18 at 05:54
  • @user184994 I ususally use the localStorage. – moritz.vieli Oct 05 '18 at 06:01
  • 1
    @Argonitas Yes, it just depends on whether you want it to persist once the session is closed – user184994 Oct 05 '18 at 06:03
  • @user184994 I need to keep user logged after browser is closed. Im using JWT tokens to keep user logged, and its very useful to use localStorage in this case: user could change the token but signature would be invalid. 'authlistener' will not be encoded so its seems unsafe in this case. – James Oct 05 '18 at 06:12
  • 1
    If you want a secure solution read this first: https://dev.to/rdegges/please-stop-using-local-storage-1i04 i would prefere cookies, because they are much saver then localStorage or sessionStorage for authentication. the localStorage and sessionStorage are good fur uncritical data like look and feel settings or widget positions etc. – JohnnyDevNull Oct 05 '18 at 07:01
  • @JohnnyDevNull do i really need a secure cookie just to store an auth state? – James Oct 05 '18 at 15:06
  • @James that is the bare minimum of what you need to store a *secure auth state. If you dont care about it being secure, go right ahead with the localstorage solution. – Devin Fields Oct 05 '18 at 17:41
  • @JohnnyDevNull okay i would rather prefer using cookies instead of local storage... can you provide an example of storing jwt token and auth state inside a cookie? (i'm using Node.js with Express) – James Oct 05 '18 at 17:53
  • 1
    @James: Read this: https://blog.angular-university.io/angular-jwt-authentication/ there is expressJS used and i have used this approach also in my app. – JohnnyDevNull Oct 05 '18 at 20:45
  • 1
    @James: ... and also dont'f forget to set the config, that angular will receive the cookie: https://stackoverflow.com/a/30602940/3634274 – JohnnyDevNull Oct 05 '18 at 20:50
  • @JohnnyDevNull thanks. This last link is driving me mad. I set `cors` in `express` like this: `const corsOptions = { origin: 'https://localhost:4200', credentials: true } app.use(cors(corsOptions));` , also tried to use `with credentials: true` inside an `auth interceptor` and it doesnt work... the cookie never gets created – James Oct 05 '18 at 21:08
  • @JohnnyDevNull auth interceptor: `intercept(req: HttpRequest, next: HttpHandler): Observable> { return next.handle(req.clone({ withCredentials: true })); }` – James Oct 05 '18 at 21:22
  • are there generally some request errors you receive? – JohnnyDevNull Oct 05 '18 at 21:52
  • First you schould setup your express correctly and check if the cookie comes with it. Then Second check Angular if the Cookie arrives in the Result of your Auth Endpoint. Then later in the other request you can use the interceptor – JohnnyDevNull Oct 05 '18 at 22:03
  • 1
    I can recommend you this vscode plugin: https://marketplace.visualstudio.com/items?itemName=humao.rest-client to check your express api – JohnnyDevNull Oct 05 '18 at 22:03
  • @JohnnyDevNull in chrome it works fine... i'm using HTTPS on angular cli `https://localhost:4200` however im using HTTP for node.js server `http://localhost:4000`... its not working in Firefox because of this.. i'll generate SSL certificate for server later too – James Oct 05 '18 at 22:04
  • @JohnnyDevNull API works fine... `200 OK` and there is a `set-cookie` with my cookies and `Access-Control-Allow-Credentials: true`... i can see cookie being created on Express... probably chrome isn't saving it – James Oct 05 '18 at 22:28
  • maybe you need also the other cros headers... `app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Origin, X-Request-With, Content-Type, Accept'); next(); });` – JohnnyDevNull Oct 05 '18 at 22:32
  • 1
    @JohnnyDevNull ok got it working by removing `secure: true` and `httpOnly: true`. :( – James Oct 05 '18 at 22:53
  • @JohnnyDevNull enabled SSL for both front and back-end... now i'm able to use cookie options (`secure` and `httpOnly`) as well :) – James Oct 06 '18 at 01:25
  • Good work James! – JohnnyDevNull Oct 06 '18 at 06:37

0 Answers0