Search code examples
angularcookiesserver-side-renderingangular-universalsetcookie

Angular Universal set set-cookies in request header


I have anngular Universal SSR application with authentication. I save auth token inside http cookies(set-cookies). Now when I refresh application I see unauthenticated page at first, and after a second it converts to authenticated state.

I understand that this happens because Universals renderer server doesn't pass token from cookies to API when rendering page. So how can I force Universal server to render page in authenticated state?


Solution

  • Angular universal does not transfer cookies when using HttpClient (github issue). You can add them manually, using an interceptor.

    interceptor.ts

    import { REQUEST } from '@nguniversal/express-engine/tokens';
    
    @Injectable()
    export class CookieInterceptor implements HttpInterceptor {
      constructor(@Optional() @Inject(REQUEST) private httpRequest) 
      {
      }
    
      intercept(req: HttpRequest<any>, next: HttpHandler) {
        if (this.httpRequest) //If optional request is provided, we are server side
        {
          req = req.clone(
          { 
            setHeaders: 
            {
                Cookie: this.httpRequest.headers.cookie
            }
          });
        }
        return next.handle(req);
      }
    }
    

    You might get the following error

    Refused to set unsafe header 'Cookie'

    A possible workaround, suggested in this comment, is to bypass xhr2's default security behaviour for unsafe headers

    For angular 7 (and I guess 8), the following works

    server.ts

    import * as xhr2 from 'xhr2';
    xhr2.prototype._restrictedHeaders = {};
    

    I haven't tested for angular 9, but I think you need a different workaround for the unsafe cookie header

    // activate cookie for server-side rendering
    export class ServerXhr implements XhrFactory {
      build(): XMLHttpRequest {
        xhr2.prototype._restrictedHeaders.cookie = false;
        return new xhr2.XMLHttpRequest();
      }
    }
    
    @NgModule({
      ...
      providers: [{ provide: XhrFactory, useClass: ServerXhr }],
      ...
    })
    export class AppServerModule {}