0

I'm pretty new to Node.JS asynchronous behavior and I'm using it within the Auth0 solution to authenticate user. Basically you can create a Custom Database where you can write your own login code, but the issue is more Javascript related than Auth0 anyway.

Here is my code (I'm omitting some functions because they are unrelevant to my issue) :

function login(email, password, callback) {
    const request = require('request'); 
    const url = "<URL>";
    const audience = "<URL>";
    const DB1 = "db1";
    const DB2 = "db2";

    callAuth0DB(email, callback).then(jsonUser =>  {
        console.log("jsonUser", jsonUser);
        callback(null, jsonUser)
    });    

    console.log("Async too late");

    function callAuth0DB(email, callback) {
        return new Promise((resolve) => {
            let jsonUser = {};

            //DB 1
            const optionsDB1 = configureDBRequest(email, password, DB1);

            request(optionsDB1, function(error, response) {
                if (error) {
                    console.log(error);
                    throw new Error(error);
                }
                let body = JSON.parse(response.body);

                try {
                    let token = JSON.parse(
                        Buffer.from(body.access_token.split(".")[1], "base64").toString()
                    );
                    callback(null, {
                        user_id: token.sub,
                        email: email,
                    });
                } catch (e) {
                    //DB 3
                    console.log("Trying DB 2");

                    const username = email.substring(0, email.indexOf("@"));
                    const commonUsername = username.substring(0, username.indexOf("+"));

                    getApiToken().then(apiToken => getUsers(apiToken, commonUsername).then(async users => {
                        for (let u of users) {
                            const optionsDB2 = configureDBRequest(u.email, password, DB2);

                            authUser(optionsDB2, u.email)
                            .then(sub => {
                                //Case 1
                                if (sub) {
                                    jsonUser = {
                                        user_id: sub,
                                        email: u,
                                    };
                                } 
                            })
                            .catch(e => {   
                                if (JSON.parse(e).error !== "invalid_grant") {
                                    //Case 2
                                    console.log("u", u);
                                    jsonUser = u;
                                } 
                            });
                            
                        }
                                        
                    }));
                }
            });
            resolve(jsonUser);
        });
    } 
}

My issue is that everything works fine.

My jsonUser contains exactly what I need but as it is asynchronous, the callback function (which is why I have to return) execute after my log console.log("Async too late");. This causes Auth0 to never take my callback response and fails.

Is there a way to actually wait for my callback to execute before continuing ?

EDIT

I can had a log to show what's happening :

3:17:07 PM:     new webtask request
3:17:07 PM:     jsonUser {}
3:17:07 PM:     finished webtask request
3:17:07 PM:     Trying DB 2 
3:17:07 PM:     new webtask request
3:17:07 PM:     Redirecting is not possible in a 'oauth2-password' flow or when prompt=none. Skipping redirect.
3:17:07 PM:     finished webtask request
3:17:07 PM:     u {
user_id: '<user_id>',
email: '<email>'
}

EDIT 2

This is different from How do I return the response from an asynchronous call? as I do not have hands on what's calling the login function and cannot define things outside it.

JeremP
  • 47
  • 1
  • 13
  • If you want to run code after your callback, then put that code *after the callback*. You're putting it after the whole `then()` so it will run while the main event loop waits for the promise to resolve. – Quentin Dec 21 '22 at 14:19
  • You shouldn't be using a callback here though. You're already partially using promises. You should be returning a promise from `login` and then using `then` in whatever code calls it. – Quentin Dec 21 '22 at 14:22
  • You mean put all my functions outside my `login` function ? That's not possible, Auth0 blocks creating other functions outside. I have no hands on what's calling the `login` function – JeremP Dec 21 '22 at 14:33

0 Answers0