[SOLVED] How to sign custom message

Iโ€™m working in project which require to use third party APIs
some functions in the api require authentication so Iโ€™m using JWT tokens

:point_down: :point_down: :point_down: :point_down: here is APIs Authentication flow and the problem i get when using moralis

The code Iโ€™m using for this flow

// the  generateChallenge and   authenticate  is   created  in  another  file 
// `signMessageAsync` lets us programatically request a message signature from the user's wallet
 const { signMessageAsync } = useSignMessage();
 //  authenticate  method  from  moralis 
   const {authenticate, account}  =  useMoralis()
   // sign in  function
  const signIn = async () => {
    try {
      // check  if  there  is  no  connected  address 
      if (!account) {
        return alert('Please connect your wallet first');
      }
       //I'm  using  user  address to  generate  challenge
      const challenge = await generateChallenge(account);
      //I'm  using user  address   to  sign  message 
      const signature = await signMessageAsync({message : challenge });
      //  I'm  getting  access  token  
      const accessToken = await authenticate(account, signature);
      console.log( {accessToken});
      //  I'm  user  access Token  sessionStorage
     window.sessionStorage.setItem('accessToken', accessToken);
    } catch (error) {
      console.error(error);
      alert('Error signing in');
    }
  };

The problem Iโ€™m facing :point_down:

when I hit the signIn button meta mask pops-up to sign message :point_down:

The problem starts here

after clicking Sign Button the metamsk pop-up again to sign the moralis message see here :point_down:

so instead of getting the lens API access tokens it returns moralis access token / perserUser object
What Iโ€™m looking for is to make sure the metamask popโ€™s up once / one time to sign the message from lens API

then return the access token from lens api

This may pop up MetaMask again with Moralis authentication

What for are you using lens authentication?

Iโ€™m using their API to handle POST/MUTATE operations to their off chain db
and mutate functions require authentication
tried to use their Smart contract but it seems like their SC is too complex some function canโ€™t be interacted via moralis

Any idea how i can do that

What exactly are you trying to do? It looks like you are calling two authentications and that is why you see two messages to sign

Yes I am calling two authentication the first auth is to make sure user is authenticated to my moralis DB the second authentication Iโ€™m calling is to connect user to lens-protocol DB, so user can handle mutation operations
why I want to do this using moralis
usually for user to sign in to lens-protocol first will have to connect wallet, so We can get user wallet address and use that address to request challenge and sign the challenge with

and i wanted to use Moralis as my back-end so i can add logic to my DB like gamification etc

What part doesnโ€™t work? Where you have issues? If you call Moralis authentication then that MetaMask pop up will show to sign a message.

I decided to record these two short clips showing the problem part

as i said, i want to be able to connect wallet and authenticate my users using moralis authenticate Hook

and then use connected/ authenticated account to request challenge and sign challenge from lens API

1- This example shows when i use RainbowKit as connect wallet method

click here to watch as you can see here when i use RainbowKit after connecting wallet and metamsk pop up show with sign button and after signing the message there is no second pop up and i can see the access token from lens
thatโ€™s what i want to achieve using moralis instead of RainbowKit

1- This example shows when I use Moralis as connect wallet method
click here to watch
as you can see here after signing lens API message instead of sending the signed challenge to lens API metamask pop up shows with another challenge from moralis challenge to sign / authenticate and in the tab of sessionStorage i canโ€™t get the token

Any idea

In the original code that you posted, it looks like you sign a challenge for lens, and right after that you call authenticate for Moralis. You should somehow finish that authentication for lens and get a token from lens.
Moralis has his own authentication with his own token and will require a specific format for the signed message.

I have no idea how i can prevent moralis from re-authenticating as demonstrated in clip this happens automatically when I call the sign-in function, :point_down:
Here is a full overview / Full code of SignIn function Give it a look , We can identify the bug source

//  the  get  challenge    this  is  the  function  i  use  to  get  challenge  from lens-api
const GET_CHALLENGE = `
query($request: ChallengeRequest!) {
    challenge(request: $request) { text }
}
`;

export const generateChallenge = async (address) => {
const res = await apolloClient.query({
    query: gql(GET_CHALLENGE),
    variables: {
        request: {
            address,
        }
    }
});
return res.data.challenge.text;
}

//Authenticate   function 

const AUTHENTICATION = `
mutation($request: SignedAuthChallenge!) {
authenticate(request: $request) {
  accessToken
  refreshToken
}
}
`;

export const authenticate = async (address, signature) => {
const { data } = await apolloClient.mutate({
mutation: gql(AUTHENTICATION),
variables: {
  request: {
    address,
    signature,
  },
},
});
return data.authenticate.accessToken;
};

//  SignText    this  is  a  function  used  to  sign  text  

//  First  I  initialize  the  provider  like  this  :point_down:

 const ethersProvider = new ethers.providers.Web3Provider(window.ethereum);

// SignText  function  :point_down:

 const signText = (text) => {
     console.log("sign me ")
    return ethersProvider.getSigner().signMessage(text);
  }

//   Full code  of  SignIn function :point_down:

//  Sign-in function
    const signIn = async () => {
      // check  if  user is  authenticated
      try {
        if (!isAuthenticated || !account) {
          return alert('Please connect your wallet first');
        }
        // generate  challenge 
        const challenge = await generateChallenge(account);
        //  sign  genereted  challenge
        const signature = await signText(challenge);
        // Get  access Token 
        const accessToken = await authenticate(account, signature);
        console.log({accessToken});
        // Store  access token  sessionStorage
        window.sessionStorage.setItem('accessToken', accessToken);
        
      } catch (error) {
        console.error(error);
        alert('Error signing in');
      }
    };

you have to read the documentation for lens, to see how to submit that signature to validate it, the code that is wrote there signs a message for lens, and then it calls moralis authentication, and it will not work like that, moralis authentication doesnโ€™t know how to handle that signature from lens, you have to submit it to lens somehow

I tried to re-read their docs again, but I think this issue is not related to lens-api why it works when i use another methods to connect but not moralis ?

As you stated here, using account, and signature may pop up metamask again for authentication. And this is what is happening :hot_face:

what tricky i can use instead of moralis authentication pop up to just sign lens challenge

Heey @cryptokid thank you for your help, I managed to solve it. I had to change the custom function name from authenticate to something else, since authenticate is the name of authenticate methods from moralis

1 Like