Accounts.validateNewUser() is ignored when using async function?

I’m trying to prevent creation of a new user account when using Meteor.loginWithGoogle() specifically when the user selects “Sign In” (vs “Sign Up”).

Accounts.validateNewUser(async function(user) {
    const idToken = user?.services?.google?.idToken
    if (idToken) {
        const LoginTicket = await getDecodedOAuthJwtGoogle(idToken)
        if (LoginTicket?.payload?.nonce === 'login') {
            console.log('Abort createUser')
            return false
        }
    }
    return true
})

Even though I can confirm it’s a login and return “false” to prevent the creation of a new user as per the docs, I find a a new user account still being created?!

As a test, trying the following did indeed prevent the user account from being created.

Accounts.validateNewUser(function(user) {
    return false
})

It appears that the use of async / await in Accounts.validateNewUser() is the problem? Any workarounds for this?

A few potential ways that might work as alternate ways to accomplish what I’m trying to do are:

  1. Is there another way to let Accounts.validateNewUser() know the external login is a login attempt and not a registration using a technique that would not require the use of an async function? I currently use the “nonce” to pass that indicator:
Meteor.loginWithGoogle({
    requestPermissions: ['email'],
    loginUrlParameters: { nonce: 'login' } //<- nonce is the only parameter that can be later retrieved. Need different logic flow if registration vs login
}, function(error, result) {
    if (error) {
        ...
    } else {
        ...
    }
})
  1. I was able to use the new Google Identity Services SDK to create my own “Sign In With Google” button and could get the authentication to work, but I’m stuck on the rest of the workflow of tying that into a successful Meteor account session. (This proposed solution might however work.)

I think Meteor validateNewUser doesn’t support async function. You can find this block of code in accounts-base package.

    this._validateNewUserHooks.forEach(hook => {
      if (!hook(fullUser)) throw new Meteor.Error(403, "User validation failed");
    });

To supports async, it should be:

   this._validateNewUserHooks.forEach(async (hook) => {
      if (!(await hook(fullUser))) throw new Meteor.Error(403, "User validation failed");
    });
1 Like

Meteor has Meteor.wrapAsync function, I think it may solve this problem.
What if you call it instead?

Accounts.validateNewUser(Meteor.wrapAsync(async function(user) {
    const idToken = user?.services?.google?.idToken
    if (idToken) {
        const LoginTicket = await getDecodedOAuthJwtGoogle(idToken)
        if (LoginTicket?.payload?.nonce === 'login') {
            console.log('Abort createUser')
            return false
        }
    }
    return true
}))