1

I have the problem on the server side, when I refresh page there is no way to retrieve jwt token on server from local storage because of localstorage only exists on the browser. Also when I log in I save token in the transfer state and again after the page is refreshed state variable disappear, is it normal behavior? Is there any solution for this issue?

Here is my interceptor:

import { Injectable, Injector, Inject, PLATFORM_ID } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/observable/throw'
import 'rxjs/add/operator/catch';
import { makeStateKey, TransferState } from '@angular/platform-browser';
import { isPlatformServer, isPlatformBrowser } from '@angular/common';

const AUTH_STATE = makeStateKey<string>('authState');

@Injectable()
export class MyHttpInterceptor implements HttpInterceptor {
    private isServer: boolean;

    constructor(private tstate: TransferState, @Inject(PLATFORM_ID) private platformId) {
        this.isServer = isPlatformServer(platformId);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        console.log("intercepted request ... ");
        let authReq: any = req;

        if (this.tstate.hasKey(AUTH_STATE)) {
            // We are in the browser
            authReq = req.clone(
                {
                    headers: req.headers.set("Auth", this.tstate.get(AUTH_STATE, ''))
                }
            );

            console.log("CLIENT")
            console.log(this.tstate.get(AUTH_STATE, ''))
        } else if (this.isServer) {
            // We are on the server
            authReq = req.clone(
                {
                    headers: req.headers.set("Auth", "fromServer")
                }
            );

            console.log("SERVER")
        } else {
            // State not transfered
            let token: any;
            token = window.localStorage.getItem("token");

            if (token) {
                authReq = req.clone(
                    {
                        headers: req.headers.set("Auth", token)
                    })

                this.tstate.set(AUTH_STATE, token);
            }

            console.log("BROWSER")
        }
        console.log("Sending request with new header now ...");

        //send the newly created request
        return next.handle(authReq)
            .catch((error, caught) => {
                //intercept the respons error and displace it to the console 
                console.log("Error Occurred");
                console.log(error);
                //return the error to the method that called it
                return Observable.throw(error);
            }) as any;
    }
}

This part: headers: req.headers.set("Auth", "fromServer") "fromServer" should be replaced with correct token which is in local storage...

Vladimir
  • 1,751
  • 6
  • 30
  • 52

1 Answers1

0

You are already using this.isServer for code you want to only run on the server. Any use of localStorage needs to be similarly be wrapped in this.isBrowser or if (isPlatformBrowser(this.platformId)) {}

As you said, you won't be able to store a token in localStorage and then retrieve it server-side. You either wrap it in the browser check or you store the token somewhere you can read (e.g., a DB).

See this answer for an alternate way to store: How to use localStorage in angular universal?

beachCode
  • 3,202
  • 8
  • 36
  • 69
  • I know that what. Is there any solution for this problem? – Vladimir Jan 15 '18 at 20:09
  • @Vladimir can you please clarify? You can't use localStorage server-side so you either wrap it in the browser check or you store the token somewhere you can read (e.g., a DB). That's the only solution. – beachCode Jan 16 '18 at 00:56
  • But then I can send a header on the server side, so auth will be only on client side that is the main problem. – Vladimir Jan 16 '18 at 19:16
  • @Vladimir I'll give you an example. Let's say I'm showing data from a user's Google calendar. To authenticate, I get a token from Google and store it in localStorage so I don't have to get it again. I use that token to ask for their appointments. In Angular Universal, I can't store the token in localStorage, so if I have to have that token in my server-side code, I either store it in a DB or I ask Google for it each time I need it. When it comes to showing the appointments, I don't run that code server-side. I wrap that code in the platform check and only run it in the browser. Make sense? – beachCode Jan 16 '18 at 20:08
  • Sorry but no. To ask for token each time on the server side you will need to store user and password somewhere on server side also if you are able to store it in the database how you will retrieve token for particular user later? Also for showing appointments, you will need tokens on the server side it will blink if you don't have because of different data on the server and client-side... – Vladimir Jan 18 '18 at 09:05