Unable to Post between routes

I have setup a Node.js and express web application using Okta User Authentication. I have leveraged the [okta-oidc-js package](https://github.com/okta/okta-oidc-js/blob/master/packages/oidc-middleware/README.md) to do this.

I am able to successfully authenticate users as well as protect particular routes with the oidc.ensureAuthenticated() middleware. The issue I am hitting is I am not sure how to complete a post request to a route that is protect by oidc.ensureAuthenticated() middleware.

I have data stored in one protected route routeA which I want to post the data via axios to routeB when I do this I receive a 401 response.

I assume this is because I need to add some authorization headers from the user that is authenticated to my axios post request, but I am unsure if or which ones to pull from the const tokenSet = req.userContext.tokens; or const userinfo = req.userContext.userinfo; endpoints and how to set the headers.

If I remove the oidc.ensureAuthenticated() from the route everything works as expected so I just would like some information on how I can make a post request for an already authenticated user. Any links to doco would be appreciated or an example post request.

Cheers.

Hi @Cass0wary! Can you elaborate more on this step:

I have data stored in one protected route routeA which I want to post the data via axios to routeB when I do this I receive a 401 response.

Are you making an XHR post or a backend POST request?

Hi @sigama thanks for responding. I am using Axios which I believe uses XMLHttpRequests under the hood.

Here is the request, not sure if this helps

POST /es/ingest/b/t 401 0.520 ms - 12
Error: Request failed with status code 401
    at createError (login-portal/node_modules/axios/lib/core/createError.js:16:15)
    at settle (login-portal/node_modules/axios/lib/core/settle.js:17:12)
    at IncomingMessage.handleStreamEnd (login-portal/node_modules/axios/lib/adapters/http.js:260:11)
    at IncomingMessage.emit (events.js:326:22)
    at endReadableNT (_stream_readable.js:1252:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21) {
  config: {
    url: '/es/ingest/b/ts',
    method: 'post',
    data: '{"data":[{..},{...},{...}]}',
    headers: {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json;charset=utf-8',
      'User-Agent': 'axios/0.21.1',
      'Content-Length': 113195
    },
    baseURL: 'http://localhost:3000',
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 3000,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus]
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      socket: [Function (anonymous)],
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      timeout: [Function (anonymous)],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'localhost',
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: null,
      _server: null,
      parser: null,
      _httpMessage: [Circular *1],
      [Symbol(async_id_symbol)]: 744,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    _header: 'POST /es/ingest/b/ts HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/json;charset=utf-8\r\n' +
      'User-Agent: axios/0.21.1\r\n' +
      'Content-Length: 113195\r\n' +
      'Host: localhost:3000\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 80,
      protocol: 'http:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'fifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    path: '/es/ingest/b/ts',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [Socket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 401,
      statusMessage: 'Unauthorized',
      client: [Socket],
      _consuming: true,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'http://localhost:3000/es/ingest/b/ts',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(RequestTimeout)]: undefined
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'localhost',
    protocol: 'http:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 113195,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'http://localhost:3000/es/ingest/b/ts',
      _timeout: Timeout {
        _idleTimeout: -1,
        _idlePrev: null,
        _idleNext: null,
        _idleStart: 2235827,
        _onTimeout: null,
        _timerArgs: undefined,
        _repeat: null,
        _destroyed: true,
        [Symbol(refed)]: true,
        [Symbol(kHasPrimitive)]: false,
        [Symbol(asyncId)]: 750,
        [Symbol(triggerId)]: 746
      },
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'content-type': [Array],
      'user-agent': [Array],
      'content-length': [Array],
      host: [Array]
    }
  }, 

I am not querying a different url on a different port or anything like that.

I create my axios client like so:

const esapi = axios.create({
    baseURL: keys.app_web_server_addr+':'+keys.app_web_server_port,
    timeout: 3000,
    });  

and then use the client later via a function call later:

let callEs = (url, data) => {
  // post request completed by axios.  
  esapi.post(
        url,
        {data})
    .catch( err => console.log(err))
}

How does the oidc.ensureAuthenticated() function ensure the client is able to access the page? Do I need to add in the id_token I receive from req.userContext.tokens in the headers or something to let the oidc.ensureAuthenticated() function know I am authenticated?

Out of curiosity how would the implementation change if I was making XHR vs Backend Request

If there is something else I can do to confirm please let me know

Hi @sigama sorry to ping, I am still yet to work this one out, even if you could point me in the right direction.

@Cass0wary Can you please open a support ticket through an email to support@okta.com with this issue? One of our Support Engineers will take the case and assist you in narrowing down the cause of the issue. Thanks

@Lijia thanks I have opened a case.

Hey @Lijia and @sigama can I please get some help on this one?

I was able to resolved this.

The issue was that I was making a post request with axios which was a new client instance so it did not have any scope of the current request headers. I had to get the current headers from the request and append them to my axios post request.

let config = {
    headers : {
      cookie: req.headers.cookie
    }
  }

esapi.post(url,data,config)

The only important part of the cookie is the connect.sid=COOKIE_GOES_HERE'

Another example using curl:

curl -X POST http://localhost:3000/route \
  -H 'Content-Type: application/json' \
  -H 'Cookie: connect.sid=COOKIE_GOES_HERE' \
  -d '{"text": "hello again!", "toUserId": "USER_ID_COPIED_FROM_OKTA_DASHBOARD_URL"}'

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.