In what way can I utilize the request object within a promise that is nested?

I am currently working on a Nuxt server side rendered application using the express framework for authentication with the openid-client package. My goal is to store the retrieved token in the express session, but I am facing an issue where the request model (req) is always undefined in the callback promise. I want to achieve this by assigning req.session.token = tokenSet.access_token. As a beginner in JavaScript, I believe I might be overlooking something obvious.

I have experimented with different approaches to pass variables into a JavaScript promise, but they all required defining the Promise manually, which is not applicable in my situation. I also attempted to wait for the promise and use it outside of the callback promise without success.

router.get('/api/oidc-callback', (req, res, params) => {
  Issuer.discover('http://localhost:5000') // => Promise
    .then(function(identityIssuer) {
      const client = new identityIssuer.Client({
      ...
      })
      // REQUEST DEFINED HERE
      console.log(req)
      client
        .callback('http://localhost:3000/api/oidc-callback', req.query, {
          code_verifier
        })
        // => Promise
        .then(function(tokenSet) {
          // REQUEST BECOMES UNDEFINED HERE
          console.log(req)
          req.session.token = tokenSet.access_token
        }, req)
        .catch(error => {
          console.log(error)
        })
//I also tried using it outside
      res.redirect('/oidc-callback')
    })
})

Thank you in advance for any assistance!

Answer №1

Within your code, you currently have a scenario where you have two nested asynchronous operations and attempt to execute something at the end of the first .then() handler:

Issuer.discover().then(function() {
    client.callback().then(function() {
       // ...
    });
    res.redirect('/oidc-callback');
});

This leads to the issue where res.redirect() is called before client.callback() completes because there is no mechanism in place to ensure that it waits for the completion of client.callback(). This results in the response being sent and a redirect being triggered before modifying the session, which is not the desired behavior. To resolve this, you can take one of the following approaches:

1) Move the res.redirect() inside the inner .then() block as shown below:

Issuer.discover().then(function() {
    client.callback().then(function() {
       // ...
       res.redirect('/oidc-callback');
    });
});

2) Introduce a return before client.callback() to chain the inner promise to the outer one. This way, the outer promise will not resolve until the inner one is completed, allowing you to add another .then() handler for the res.redirect():

Issuer.discover().then(function() {
    return client.callback().then(function() {
       // ...
    });

}).then(function() { // executed after both asynchronous operations are finished res.redirect('/oidc-callback'); });

Option #2 is recommended for simpler error handling, as all error handling can be consolidated in one place at the top level. Combining all these changes, your code can be revised as follows:

router.get('/api/oidc-callback', (req, res, params) => {
    Issuer.discover('http://localhost:5000').then(function(identityIssuer) {
        const client = new identityIssuer.Client({
            ...
        })
        return client.callback('http://localhost:3000/api/oidc-callback', req.query, {
            code_verifier
        }).then(function(tokenSet) {
            console.log(req);
            req.session.token = tokenSet.access_token
        }, req);
    }).then(() => {
        res.redirect('/oidc-callback');
    }).catch(err => {
        console.log(err);
        res.sendStatus(500);
    });
});

Additionally, proper error handling has been included at the end to ensure that no response is sent until both asynchronous operations are complete. If either operation encounters an error, a suitable error response will be sent.

Answer №2

One possible explanation for req being undefined is that the promise was resolved after the middleware execution (res, req, next) => {...}. To address this issue, consider returning the top-level promise in the middleware like this: (res, req, next) => { return Issuer.discover(...) }, and make sure to add a return statement before client.callback(...).

router.get('/api/oidc-callback', (req, res, params) => {
  return Issuer.discover('http://localhost:5000') // <-- added return here
    .then(function(identityIssuer) {
      const client = new identityIssuer.Client({
      ...
      })
      // DEFINED HERE
      console.log(req)
      return client  // <-- added return here
        .callback('http://localhost:3000/api/oidc-callback', req.query, {
          code_verifier
        })
        // => Promise
        .then(function(tokenSet) {
          // UNDEFINED HERE
          console.log(req)
          req.session.token = tokenSet.access_token
          res.redirect('/oidc-callback')
        }) // removed , req here, it is not needed
        .catch(error => {
          console.log(error)
        })
    })
})

Adding the return statement informs express that you are running an async function, ensuring that express waits for the middleware to resolve before moving on to the next middleware.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I'm experimenting with incorporating images into a card component using the map function in JavaScript. All aspects of the card are functioning properly except for the image

import React from 'react' import Card from '@material-ui/core/Card'import CardMedia from '@material-ui/core/CardMedia'; import CardContent from '@material-ui/core/CardContent'; import {makeStyles} from '@materia ...

I'm seeking clarification on the composition of Objects in Node.js

After running a console.log on a parameter from the callback function in the Node.js formidable package, here is the output of files: { fileUpload: [ PersistentFile { _events: [Object: null prototype], _eventsCount: 1, _maxListene ...

Unable to display Three.JS OBJ Model

I am facing an issue with loading a .obj model in Three.js. I created the model in Cinema 4D, exported it with a scale of 1 meter, and tried to load it using OBJLoader in Three.js. However, even though there are no errors, the model is not showing up. Wh ...

Sorting in MongoDB can be done easily using the $sort operator,

Is it possible to arrange elements based on a given array? For example: const somes = await SomeModel.find({}).sort({'_id': {'$in': [ObjectId('sdasdsd), ObjectId('sdasdsd), ObjectId('sdasdsd)]}}).exec() I am seeking a ...

Tips on creating adaptable images for mobile viewing

My coding conundrum involves the use of two columns - one for an image and the other for a description of that image. However, when viewing my site on mobile devices, the image is cut off at only half its height. Adjusting both columns to col-sm-6 results ...

What is the best way to convert a recordset to an array using React?

I'm attempting to create an array by retrieving data from a SQL recordset: +------------+------------+------------+ | start_type | field_name | start_text | +------------+------------+------------+ | 0 | Field1 | some text. | +----------- ...

javascript/AngularJS - make elements gradually disappear

I need help implementing a fade effect for an icon in the middle of a picture that indicates scrollability to the user. Currently, when the user scrolls, I can hide the icon but would like to add a nice smooth fade-out effect. Here is the HTML code snippe ...

Expressjs makes it easy to upload audio files to your website

Currently, I'm developing a music app and I'm looking for the best way to upload an audio file in my ExpressJS application. Is it possible to use Cloudinary or is there another method that is more efficient? I attempted to follow the same proces ...

Using a jquery function within a Laravel view

I am trying to retrieve a selected item from a dropdown menu using jQuery and then redirect it to a controller function. This function will return some data to be displayed based on the selected item. I could really use some assistance with this. Here is m ...

Developing an HTML table with the power of JavaScript and JSON

I am having difficulty creating an HTML table using JavaScript with JSON input. In my code, I'm using a placeholder in the HTML that will be filled by a innerHTML call in Javascript: for (var i = 0; i < json.data.length; i++) { listItem = json. ...

Steps for incorporating monaco-editor into a website without utilizing nodejs and electron

Currently, I am working on building a basic web editor and came across Monaco-editor. I noticed someone using it with Electron, but I am interested in integrating it into plain JavaScript just like on their webpage (link). However, I am struggling to fin ...

Guide on incorporating file uploads in an Angular 6 project

I am currently working on creating a component where I have implemented a file upload function in a child component and am attempting to use that component's selector in another one. Here is my project structure: - upload : upload.component.html up ...

Ensure that when adjusting the height of a div, the content is always pushed down without affecting the overall layout of the page

My webpage contains a div element positioned in the middle of the content, with its height being adjustable through JavaScript code. I am seeking a way to manage the scrolling behavior when the height of the div changes. Specifically, I want the content t ...

Is there a way to prevent the entire row from being selected when a radio button is clicked in an md-data

Can anyone assist me with an issue I am having with my data table? When I select a radio button, the entire table row is getting selected instead of just the radio button. Below is the code snippet: https://i.sstatic.net/dicwF.png My Expectation: When c ...

When using SuperTest, the Authorization header value may unexpectedly return undefined

Currently, I am working on writing tests using Mocha, Supertest, and Chai. In order for my API's to function properly, they require an Authorization header which can be obtained from req.headers["authorization"]. Below you will find the current setup ...

Receiving a 405 error when making an API call - could the routing be misconfigured? (Using NextJS and Typescript)

Hey there, I've been working on implementing a custom email signup form that interfaces with the Beehiiv newsletter API. If you're interested, you can take a look at their API documentation here: Beehiiv API Docs Currently, my web application i ...

Hey there, I'm looking to use different CSS fonts on Windows and Mac for the same page on a web application. Can someone please guide me on how to accomplish this?

In order to tailor the font based on the operating system, the following criteria should be followed: For Windows: "Segoe UI" For Mac: "SF Pro" Attempts have been made using the code provided below, but it seems to load before the DOM and lacks persisten ...

How do I go about adding a specific class to every row within a Vue.js table?

I have an html table structured like this : <tbody> <tr v-for="employee in employees" :key="employee.EmployeeId" @dblclick="rowOnDblClick(emplo ...

I'm encountering an issue with Regex.test

When working with the following JavaScript code... $.post(url, data, function (json) { var patt = new RegExp('/^\[{"dID":/'); if (patt.test(json)) { //output json results formatted } else { //error so o ...

Deactivate a button when clicked on a card that has been mapped

After creating a card component and mapping through each card, I added an onClick function to disable the button of the clicked card. However, my logic ended up disabling all buttons instead. Here is the code snippet where I define the rendering of the UI ...