[SOLVED] Web3Auth & Magic Link do not restore session when user is already logged in

Iā€™m testing out other wallet providers and ran into the same issue with both Wallet Connect and Magic Link:
Iā€™m using my app with Metamask, then I log out of the app with the metamask user.
When I log in with another wallet provider (WC/Magic) the auth works but when I try run a contract method like buying an NFT, I get a revert saying ā€œcannot buy from yourselfā€. It turns out the signer is still the address from metamask!

web3.getSigner() still has the old metamask address and not the one from the new provider.


and so itā€™s sending from the address and not the one logged in with Magic Link or WC:

Only after I fully Disconnect metamask from the site, revoke the connection, it will work and gives the right address:

Since this is for both WC and Magic thereā€™s something not right in setting the alternative provider when metamask is still ā€˜connectedā€™ though not logged in.

Ok I think this is related to me not setting the provider correctly when initiating the new user :slight_smile:
It was authenticating fine but doing transactions is where it became funky.

await Moralis.enableWeb3({provider: 'magicLink'})
1 Like

@cryptokid still weird stuff happening though: why I get an email not provided error when doing this:

function loginMagic() {
    Moralis.authenticate({ 
      provider: 'magicLink',
      email: '[email protected]',
      apiKey: 'pk_live_xxx',
      network: 'rinkeby',
    })
    .then((user) => {
      Moralis.enableWeb3({ provider: "magicLink" })
      console.log('Magic user', user);
      console.log(user.get('ethAddress'))
    })
}

MagicWeb3Connector.js from Moralis SDK:

export default class MagicWeb3Connector extends AbstractWeb3Connector {
  type = 'MagicLink';
  async activate({ email, apiKey, network }) {
    let magic = null;
    let ether = null;

    try {
      await this.deactivate();
    } catch (error) {
      // Do nothing
    }

    if (!email) {
      throw new Error('"email" not provided, please provide Email');
    }
    if (!apiKey) {
      throw new Error('"apiKey" not provided, please provide Api Key');
    }
    if (!network) {
      throw new Error('"network" not provided, please provide network');
    }

I see a different syntax here:

Thanks for the input, totally sharp, I was looking at an older version. However, Iā€™m using the correct version in my bare bone test setup from https://unpkg.com/moralis/dist/moralis.js

Still throws the same error, caused by calling Moralis.enableWeb3({ provider: "magicLink" }) when a user has been found. Not only after login, but also on reloading the page and user session.

Will test some more.

On localhost it also throws errors when loading magic as you can see. Hereā€™s the Chromium log:

Not sure what thatā€™s about yet, but so far connecting other providers has been a real drag. Probably working to hard :safety_vest: :partying_face:

Tried Web3Auth, same thing but asking for clientId. Ok so I did

function loginMagic() {
    Moralis.authenticate({ 
      provider: 'magicLink',
      email: '[email protected]',
      apiKey: 'pk_live_xxx',
      network: 'rinkeby',
    })
    .then((user) => {
      Moralis.enableWeb3({
        provider: 'magicLink',
        email: '[email protected]',
        apiKey: 'pk_live_xxx',
        network: 'rinkeby',
      })
      console.log('Magic user', user);
      console.log(user.get('ethAddress'))
    })
}

Seems better but not that logical? Am I missing something? Why canā€™t I call Moralis.enableWeb3() without adding in those vars againā€¦

Can you try enable web3 only with the provider type?

Ok so I was calling enableWeb() right after authenticate(), which is not needed I found out, as authenticate already adds Moralis.web3.
So logging in is fine now, but when I refresh or come back to an existing user session, Iā€™m already authenticated so I need to call enableWeb().
How do I know the provider options for the current user session?
I cannot call it with just await Moralis.enableWeb3({provider: state.provider}), this will always throw ā€˜missing clientIdā€™ or ā€˜emailā€™ or any params you need to set when connecting to an alternative provider.

For example doing this:

window.addEventListener('load', 
  async function() { 
    if (Moralis.User.current()) {
      const web3 = await Moralis.enableWeb3({ provider: 'web3Auth' })
    }
  }
})

How do you call authenticate?


const serverUrl = "hxxx";
const appId = "xxx";
Moralis.start({ serverUrl, appId });

async function login() {
  let user = Moralis.User.current();
  if (!user) {
   try {
      user = await Moralis.authenticate({ signingMessage: "Hello World!" })
      console.log(user)
      console.log(user.get('ethAddress'))
   } catch(error) {
     console.log(error)
   }
  }
}

async function loginWC() {
  let user = Moralis.User.current();
  if (!user) {
   try {
      user = await Moralis.authenticate({ provider: 'walletconnect', chainId: 4 })
      console.log(user)
      console.log(user.get('ethAddress'))
   } catch(error) {
     console.log(error)
   }
  }
}

function loginMagic() {
  let user = Moralis.User.current();
  if (!user) {
    Moralis.authenticate({ 
      provider: 'magicLink',
      email: 'xxx',
      apiKey: 'pk_live_xxx',
      network: 'rinkeby',
    })
    .then((user) => {
      const address = user.get('ethAddress')
      console.log(address)
    })
  }
}

async function logOut() {
  await Moralis.User.logOut();
  console.log("logged out");
}

document.getElementById("btn-login").onclick = login;
document.getElementById("btn-loginWC").onclick = loginWC;
document.getElementById("btn-loginMagic").onclick = loginMagic;
document.getElementById("btn-logout").onclick = logOut;

window.addEventListener('load', 
  async function() { 
    if (Moralis.User.current()) {
      const web3 = await Moralis.enableWeb3({  provider: 'magicLink'  })
      /// throws Uncaught (in promise) Error: "email" not provided, please provide Email
  });

found these fixes related to magic by now:

whichever way I look at the code, Moralis.enableWeb3() is always wanting to do a new login and I have to provide all options. So basically there is no session that can be restored on refresh, itā€™s always forcing a new login and forcing those options.
For example for Magic Link thereā€™s magic.user.isLoggedIn() to check a valid session https://magic.crisp.help/en/article/how-are-sessions-handled-with-magic-1h92t2s/
But what the MagicWeb3Connector does is always log in again when calling enableWeb3().

if the user is not logged in, then it works fine?

well not really either, on a buy order Web3Auth is throwing:

never seen that messageā€¦
I will go back to just trying WC first, but the ā€˜just one line to integrateā€™ is a bit oversold at the moment :rofl:

Can 100% confirm now I have have WC working, session is restored on refresh, transactions all good, can switch back and forth between a WC and Metamask user without issues :+1:
If the RPC stays healthy, should be fine. I did loose connection one time between the mobile and website and had to logout and login again. Will see later if I can catch that somehow to warn the user.

As for Web3Auth and Magic Link, the main issue remains that I cannot call Moralis.enableWeb3() when a user is found on refresh. Unlike WC, itā€™s asking for all options to be passed, not only the provider name.

As discussed already in this thread, this does not work for both Web3Auth and Magic:

function loginMagic() {
    Moralis.authenticate({ 
      provider: 'magicLink',
      email: '[email protected]',
      apiKey: 'pk_live_xxx',
      network: 'rinkeby',
    })
    .then((user) => {
      // all fine
      console.log('Magic user', user);
      console.log(user.get('ethAddress'))
    })
}

// enable web3 if user present
window.addEventListener('load', 
  async function() { 
    if (Moralis.User.current()) {
      const web3 = await Moralis.enableWeb3({ provider: 'magicLink' })
      // throws error missing options
    }
  }
})

Looking at the code, I would suggest to check for magic.user.isLoggedIn() and call magic.auth.loginWithMagicLink() when no user session has been found?

Hard to debug the rest if I cant refresh properly, but have been able to done some tx.

Itā€™s crazy this Magic Linkā€¦ there are no confirmation windows, no wallet(?), it just goes wowā€¦Feels funny. Question is, can I see my wallet elsewhere or should I build additional wallet features inside my app?

Hi matiyin, were you able to do any workaround to make Magic Link work? I am having the same issue you are having here.

@cryptokid did you relay or test the issue already? Magic Link is useless at the moment, and so is Web3Authā€¦

@react The workaround is to change the Moralis code or implement a custom provider. I didnt find time yet to look myself and create a PL.

I made a little review here by the way: Magic Link Authetntication

I created an internal issue for this, I donā€™t expect a fix this week.

1 Like

Hello! Now Iā€™m working to implement Moralis with Magic in React Native application. Can this issue affect my application?

Can you give an example of code/application that replicates this problem?