1

My Angular 11 (http://localhost:4200) is now talking to my node API server (http://localhost:3000). API server sends back a sessionID in a cookie, but subsequent browser request to API doesn't come with a cookie.

This is how node API sends back sessionID in a cookie

res.cookie('sessionID', 123);

F12 confirmed it's in Response Headers, Set-Cookie: sessionID=123; Path=/

Cookie is supposed auto-sent by browser along with every request. To read it in node: var mysessionid=req.cookie["sessionID"];

Tried the options mentioned in this post and github, still don't see sessionID in F12's Request Headers:

const httpOptions = 
      {
          headers: new HttpHeaders({'Content-Type': 'application/json', 'Access-Control-Request-Headers': 'content-type'}),
          withCredentials: true,
      };
this.http.post<any[]>('http://localhost:3000/anywhere', httpOptions, myData).subscribe(...);

And:

const httpOptions = 
      {
          headers: new HttpHeaders({'Content-Type': 'application/json'}),
          withCredentials: true,
          'Access-Control-Allow-Headers': 'content-type'
      };

I have an interceptor at Angular, to confirm if interceptor causing this no-cookie-sent, the above URL is excluded, meaning the header is not touched. Still cookie is not sent over to API server.

Am I doing it correctly since cookie is supposed automatically sent?

Jeb50
  • 6,272
  • 6
  • 49
  • 87
  • ive experienced something like this in the past with our react project + nodejs, we use axios for our http requests, on the request that returns the cookie i had to extract the cookie and manually update the defaults of my axios route headers. Once HTTP handler is in memory it uses what is there until you modify it, or refresh the page to obtain it - im sure angular functions similar. – alilland Jun 25 '21 at 04:31
  • @alilland can you post some sample code? – Jeb50 Jun 25 '21 at 05:43
  • This is probably happening because you're running an Angular's development server on port 4200, while the API server is running on a different port. See full answer here: https://stackoverflow.com/questions/53687239/angular-not-sending-cookie-with-request/75635435#75635435 – Lorraine R. Mar 04 '23 at 11:45

3 Answers3

1

when our node API either responds back with a valid token, or returns a refresh token we set the cookie manually like below, and also loop over axios http request definitions and update the default headers. This forces all HTTP requests going forward to have the updated token for HTTP requests going forward in the header

when our app loads we pull the token from the headers and set them to axios there on initial load

// setHTTPToken.js (UI code)

const cookies = require('../../lib/cookies')
const { AUTHTOKEN, DOMAIN } = require('../../lib/constants')
const { NINETYDAYSASSECONDS } = require('./config')
const http = require('../../lib/http')
const { cloneDeep } = require('lodash')
const log = require('../../lib/log')('containers:App:setHTTPToken')

function setHTTPToken (token) {
  log.debug('iterating over axios http methods and setting Authorization token')
  Object.entries(http).map(name => {
    const KEY = name[0]
    // we skip over any AXIOS interfaces we dont need to update headers on
    const skippers = ['ES']
    if (!skippers.includes(KEY)) {
      const headers = cloneDeep(http[KEY].defaults.headers)
      headers.common.Authorization = token
      http[KEY].defaults.headers = headers
    }
  })
  cookies.set(AUTHTOKEN, token, NINETYDAYSASSECONDS, process.env.NODE_ENV === 'production' ? DOMAIN : null)
}

module.exports = setHTTPToken

example of our http file with axios route definitions

// http.js (UI code)
import axios from 'axios'

export const OAUTH = axios.create({
  baseURL: process.env.OAUTH_API,
  headers: {
    'Content-Type': 'application/json'
  }
})

export const RL = axios.create({
  baseURL: process.env.RECEIVING_LOG_API,
  headers: {
    'Content-Type': 'application/json'
  }
})

// ...

ignore the mixing up of es5 and es6 code, webpack bundles them

E_net4
  • 27,810
  • 13
  • 101
  • 139
alilland
  • 2,039
  • 1
  • 21
  • 42
  • Thank you and appreciate your input. Finally I'm able to solve it, please see https://stackoverflow.com/questions/68171434/angular-depth-zero-self-signed-cert/68219534#68219534 – Jeb50 Jul 02 '21 at 04:18
  • @Jeb50 glad to hear – alilland Jul 02 '21 at 05:01
0

This is probably happening because you're running an Angular's development server on port 4200, while the API server is running on a different port. See full answer here.

Lorraine R.
  • 1,545
  • 1
  • 14
  • 39
-1

Finally I'm able to solve it and make them SSL, took me more than a week:(

Hope will help someone forward.

Environment:

  1. Angular 11 front-end uses 3rd-party authentication such as Google.
  2. API server is node 14.
  3. Both are httpS/SSL.

Solution:

  1. Follow this article to create trusted .crt and .key files
  2. I didn't add localhost to hosts file.
  3. Add a proxy.conf.js (or .json file with conformed format) and include it into angular.json file.
  4. No need to specify httpOption for each individual http call.
  5. API node, add the two files to server.js.

Angular Proxy.conf.js:

const PROXY_CONFIG = 
[
    {
        context: 
        [
            "/path1",      
            "/path2",
            ...
        ],
        "target" : "https://localhost:3001", // I use 3000 for non-SSL
        "changeOrigin": true,  // helps on CORS Error in F12
        "logLevel": "debug",
        "rejectUnauthorzied": true, // must be false if not specify here
        "secure": false,            // PROD must be "true", but DEV false else "UNABLE_TO_VERIFY_LEAF_SIGNATURE"
        "strictSSL": true,          // must be false if not specify here
        "withCredentials": true     // required for Angular to send in cookie
    }
]
module.exports = PROXY_CONFIG;

Angular.json (only adding "ssl": true, this is enough to run Angular 11 over SSL):

"architect": {
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "myapp:build",
            "ssl": true,
            "proxyConfig": "src/proxy.conf.js"
            ...

Angular launch.json (port 4201 is for debugging):

{
    "type": "chrome",
    "request": "launch",
    "name": "F5 against localhost",
    "port": 4201,
    "url": "https://localhost:4200",
    "webRoot": "${workspaceFolder}"
}

Node Server.js:

const fs = require("fs");
const HttpSOptions = 
    {
        key: fs.readFileSync('ssl\\server.key'),
        cert: fs.readFileSync('ssl\\server.crt')
    }
const httpSServer = httpS.createServer(HttpSOptions, app);
httpSServer.listen(3001, ()=>{console.log('httpS is on 3001');});

To verify certificates are FULLY trusted by Chrome, open one of your API URL call in Chrome, for example http://localhost:3001/path1/func/xyz, you won't see this

enter image description here

Jeb50
  • 6,272
  • 6
  • 49
  • 87
  • This answer doesn't directly answer the question above. You changed the implementation to SSL, which is a different problem than the one asked in the question. – Lorraine R. Mar 04 '23 at 10:12