node.jsreactjssspi

how to honor windows use from React js front end application when node js api is used


Before going to question, please note, I have tried many suggestions from stackoverflow as well as many other websites. There are many suggestions, but most of them truly dont solve this question straight.

My question in simple one sentence is, how to let my web server (which is a node js express based api) know, the logged windows user id (from my react js application) in an intranet application?

Till now I am able to write express based node js server which uses node-sspi library and provides me the windows user id and groups. This API is as simple as

    var express = require('express');
    var app = express();
    var server = require('http').createServer(app);
    let cors = require('cors')
    app.use(cors())


    app.use(function (req, res, next) {
    var nodeSSPI = require('node-sspi');
    var nodeSSPIObj = new nodeSSPI({
        retrieveGroups: true
    });
    nodeSSPIObj.authenticate(req, res, function(err){
        res.finished || next();
    });
    });

    app.get('*', function (req, res, next) {
        res.json({msg: '************  Server reply by user ' + req.connection.user})
    });


// Start server
var port = process.env.PORT || 3002;
server.listen(port, function () {
  console.log('Express server listening on port %d in %s mode', port, app.get('env'));
});

React App.js code is

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      msg: "Not known",
      localdata:"local status",
      status:"not set",
    };
  }
  componentDidMount() 
  {
    fetch('http://192.168.7.179:3002/',{
      method: 'GET', // *GET, POST, PUT, DELETE, etc.
      headers: {
        'Content-Type': 'application/json',
      },
    })
      .then(response => 
        {
          this.state.status = response.status;
          return response.text();
        }
      )
      .then(msg => 
        this.setState({ msg })
        );
  }
  render() {
    return (

      <div className="App"> 
      <div> LocalData is  - {this.state.localdata}</div>
      <div> Server data is - {this.state.msg} </div> 
        api call status is  - { this.state.status } 
      </div>
    );
  }
}

export default App;

In the above code, If you do API call from browser you get correct reply

http://192.168.7.179:3002/

{"msg":"************  Server reply by user IUYT\\user1"}

But, from react app

LocalData is - local status
Server data is -
api call status is - 401

in F12 window

Failed to load resource: the server responded with a status of 401 (Unauthorized)

Please suggest changes required for calling from react app.


Solution

  • After researching finally got a breakthrough yesterday. So thought to answer my own question.

    5 points to change in my example.

    1. We need to refer both client and server with IP addresses or domains for communication purposes. So I changed all api calls origin mentions to their respective IP addresses.(localhost -> 192...)

    2. In cors, we need to mention IP address and port number as origin

    3. In client side calls if we are using fetch use credentials: include or if axios use withCredentials: true
    4. In server, cors must know the origin, so include your clients ip with port
    5. Use either express-ntlm or node-sspi as your windows authenticator.

    So Total change to my code in the example is,

    In server side

        var corsOptions = {
        origin: 'http://192.168.7.179:3001',
        credentials: true,
        authenticate: true,
        authorization: true,
        optionsSuccessStatus: 200 
        }
        app.use(cors(corsOptions))
    

    instead of

     app.use(cors())
    

    and in client side add 'credentials: 'include'' as parameter to fetch.

    change

    fetch('http://192.168.7.179:3002/',{
          method: 'GET', // *GET, POST, PUT, DELETE, etc.
          headers: {
            'Content-Type': 'application/json',
          }
        })
    

    to

    fetch('http://192.168.7.179:3002/',{
          method: 'GET', // *GET, POST, PUT, DELETE, etc.
          credentials: 'include'
        })
    

    Thats it, first run api then launch when you launch your react app and you will get a prompt for windows auth. Fill in your domain credentials and server will fetch results.

    Steps 1. In browser see if server is running -> http://192.168.7.179:3002/

    {"msg":"************ Server reply by user IUYT\user1"}

    1. Check in http://localhost:3001/ result is

    LocalData is - local status

    Server data is - Not known

    api call status is - not set

    BUT

    1. In browser see if client is running -> http://192.168.7.179:3001/

    LocalData is - local status

    Server data is - {"msg":"************ Server reply by user IUYT\user1"}

    api call status is - 200