What is the proper way to wait for an async function to finish in JavaScript before returning its result?

Currently, I find myself grappling with a Google Sign-in Authentication application that comprises a React frontend and an Express backend. The hurdle I currently face lies in the validation of tokens on the backend. The documentation for this process provides the following code snippet for validating the token:

const {OAuth2Client} = require('google-auth-library');

...

const client = new OAuth2Client(CLIENT_ID);
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
}
verify().catch(console.error);

In my own project, I have implemented this code as shown below:

//verify token
async function verify(token, client) {

  const ticket = await client.verifyIdToken({
    idToken: token,
    audience: keys.google.clientID,
  });

  const payload = ticket.getPayload();
  const userid = payload['sub'];

  var message = '';
  var cookie = {};
  await User.find({email: email}, (error, user) => {
    if(error) {
      message = error;
    } else if (user.length === 0) {
      message = 'this user is not in the database';
    } else {
      message = 'this user is in the database';
      const session = new Session({
        email: email,
        session_token: token
      });
      cookie = {
        email: email,
        session_token: token
      };
      session.save((error, session) => {
        if (error) {
          console.log(error);
        } else {
          console.log('session saved');
        }
      });
      console.log(message);
    }
  });
  return Promise.resolve(cookie);
}

//receive token id from frontend, verify it, and send session back in response
router.post('/google', (req, res) => {
  const body = req.body.tokenID;
  const client = new OAuth2Client(keys.google.clientID);

  let cookie = verify(body, client).catch(console.error);

  console.log('Cookie:' + cookie);
  return res.send(cookie);
});

Despite all the async function execution, the return statement merely outputs an empty promise object. It appears I may be misusing async and await. If anyone could provide guidance on how to make the function wait for token verification and database updates before returning, I would greatly appreciate it.

Upon calling the route, my console displays the following information:

(I have anonymized personal information in the output for privacy, but the lines contain relevant data such as Gmail account information)

...
Cookie:[object Promise]
User ID: <GOOGLE ID>
Domain: <DOMAIN>
Email: <USER EMAIL>
This user is in the database
Session saved

Thank you for taking the time to read!

Answer №1

When using the "verify" function, make sure to include the "await" keyword before calling it since it is an async function. To handle any errors that may arise, simply encapsulate the function call in a try/catch block:

router.post('/google', async (req, res) => {
  const body = req.body.tokenID;
  const client = new OAuth2Client(keys.google.clientID);

  try {
    let cookie = await verify(body, client);
    console.log('Cookie:' + cookie);
    return res.send(cookie);
  } catch(error) {
    // error handling
    console.log(error);
    return res.send("error")
}
});

`

Answer №2

It seems like you may be mixing async/await with callback-based calls. While I'm not familiar with the specifics of the library you're utilizing, the typical pattern should resemble the following:

let cookie = {};
try {
    const user = await User.find({ email: email });
    if (user.length === 0) {
        console.log('This user is not in the database');
    } else {
        console.log('This user is in the database');
        const session = new Session({
            email: email,
            session_token: token
        });

        try {
            await session.save();
            console.log('Session saved');
        } catch (err) {
            console.log(err);
        }
        return {
            email: email,
            session_token: token
        };
    }
} catch (error) {
    console.log(error);
}

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

Teaching jQuery selectors to detect recently-added HTML elements

Unable to find a solution in the jQuery documentation, I am seeking help here for my specific issue. Embracing the DRY principle, I aim to utilize JavaScript to include a character countdown helper to any textarea element with maxlength and aria-described ...

Why doesn't ngSubmit function inside a modal?

I am experiencing an issue where my submit button is not activating the ng-click angular directive, and I cannot seem to identify the cause. Most people who faced a similar problem did not have their submit button placed inside their form, but I am confi ...

Gathering information from various web pages simultaneously without the need to manually navigate through each page using a webdriver

I'm new to the world of web scraping and I've successfully developed a program that allows me to extract specific, dynamic data by utilizing the selenium web driver. My current project involves scraping data from a FAQ page in order to gather in ...

Sometimes, it feels like TypeScript's async await does not actually wait for the task to complete before moving on

Recently, I have been transitioning to using the async await pattern more frequently instead of the traditional Promise syntax because it can help in keeping the code structure cleaner. After some experimentation, I felt like I had a good grasp on how to u ...

Encountering an issue of duplicate key error when using multiple v-for loops with various keys

I've encountered an issue while working on a Python application that utilizes Vue.js. A ticket came my way with an error message stating: [Vue warn]: Duplicate keys detected: ''. This may cause an update error. (found in Root) The pro ...

Encountering an error while trying to install npm formidable

Having some trouble installing the formidable JS library. It appears that https://registry.npmjs.org/formidable is currently down. I used isup.me and it seems like the registry site is completely down. Can anyone confirm if this is the issue or if there ma ...

Issue with nodes/JavaScript: Array objects not being properly updated

Being new to Javascript and Node.js, I attempted to code a simple program that generates an array of planes with varying index values. I started by defining a plane object with default values and tried to update the index value in a for loop. However, whe ...

Can someone provide guidance on creating a calculator using the Switch statement in Javascript?

Introduction to HTML: <div id="content"> <div id="calculator-container"> <form name="calc"> <!-- The form is named "calc" --> <label for="output">A Simple Calculator</label> & ...

Implementing shared socket.io for all express routes

App.js var io = socket_io(); app.io = io; var socket = require('./config/socketio')(io); var routes = require('./app/routes/index'); socketio.js: var config = require('./config'); module.exports = function(io){ io ...

Enhance Shipping Options on Your Woocommerce Cart

I am facing a challenge with providing delivery options for three different countries in my e-commerce store. I want the customer to be able to select their country and instantly see the available delivery methods without having to refresh the entire page ...

Issue: The variable THREE has not been defined within the FBXLoader code

Currently, I am utilizing the module version of three.js in order to execute imports from a client-side JavaScript file structure. The core functionality of THREE is working correctly. However, I am encountering an issue when attempting to use it with FBX ...

Deactivate user input in Knockout Kendo TimePicker

Is it possible to prevent user input in the Kendo UI TimePicker while using knockout-kendo binding? In a previous project without knockout-kendo, I was able to achieve this by using the following code (see jsfiddle example): $('#timepicker').at ...

The initial axios GET request fails to retrieve data upon the first click

Having trouble retrieving data with button click. The issue is that the data is not fetched when clicking the button for the first time, but works fine on the second click. Here's the code snippet: const learnMores = document.querySelectorAll('. ...

Please provide either a string or an object containing the proper key for TypeScript

Within my project, the languageSchema variable can either be a string or an object containing the 'Etc' key. The corresponding interface is defined as follows: let getLanguageSchema = (language: string): string => languagesSchemas[language]; ...

Error: The variable YouTube has not been declared within this context / YouTube API

In my attempt to implement a search using the YouTube Data API, I have come up with the following code. The setup involves an express generated stack with jade. #player script. // 2. This code loads the IFrame Player API code asynchronously. ...

At what point does the cleanup function in UseEffect activate the clearInterval() function?

In the process of creating a timer for a Tenzie game, there is an onClick function that changes the state of isTimerActive from false to true when a user clicks a button. The initial value of tenzie state is also set to false, but once the user completes t ...

Best Practices for Managing Asynchronous Updates in Angular Controllers

Let me explain my current setup -- I have a controller that utilizes a service to perform some tasks and then fetches data asynchronously. Right now, the data is returned after a timeout, but ideally it would involve more complex operations: This is how m ...

Analyzing latency in node.js through numerous requests

Is there a way to send multiple requests in a loop, and measure the time of each request? In PHP I'd do: require 'vendor/autoload.php'; use GuzzleHttp\Client; $client = new Client(); for ($i = 0; $i < 100; $i++) { $start = mic ...

Executing Javascript dynamically in VueJS: Learn how to run code from a string efficiently

Currently, I am developing a website with VueJS that enables selected users to upload scripts for automatic execution upon page load. For instance, here is an example of the type of script a user may input: <script src="https://cdnjs.cloudflare.com/aja ...

Template does not reflect changes made to filters in real-time

I've been working on filtering my "PriceList" collection and sorting is functioning perfectly. However, I'm experiencing some issues with implementing filters and search functionality. When I click on custom filter buttons, the template doesn&apo ...