Skip to main content
The authenticate function will return the user’s wallet address and a signed message that verifies wallet ownership. This should be the primary authentication method for your Mini App. Uses Sign In With Ethereum (SIWE) to sign a message that contains a nonce that should be generated in your backend.

Usage

import { authenticate, ChainId, TransactionResult } from '@lemoncash/mini-app-sdk';

export const MiniApp = () => {
  const [wallet, setWallet] = useState<string | undefined>(undefined);

  const handleAuthentication = async () => {
    const result = await authenticate({
      chainId: ChainId.POLYGON_AMOY,
    });
    
    if (result.result === TransactionResult.SUCCESS) {
      setWallet(result.data.wallet);
    }
  };

  useEffect(() => {
    handleAuthentication();
  }, []);
};

Parameters

type AuthenticateData = {
  nonce?: string;
  chainId: ChainId;
  requirements?: {
    claims?: ClaimKey[];
  };
}
nonce
string
If present, it must be at least 8 alphanumeric characters in length. A unique nonce for the authentication request. This should be generated in your backend and be different for each authentication attempt.
await authenticate({
  nonce: 'l3m0nc45h',
  chainId: ChainId.POLYGON_AMOY,
});
chainId
ChainId
required
The chain id to use for the authentication request. This parameter is required.
import { ChainId } from '@lemoncash/mini-app-sdk';

await authenticate({
  chainId: ChainId.POLYGON_AMOY,
});
requirements
object
Optional requirements for the authentication request.
requirements.claims
ClaimKey[]
An array of claim keys that you want to request from the user. The available claim keys are defined in the ClaimKey enum. See the Types documentation for the complete list of available claim keys.
import { authenticate, ChainId, ClaimKey } from '@lemoncash/mini-app-sdk';

await authenticate({
  chainId: ChainId.POLYGON_AMOY,
  requirements: {
    claims: [ClaimKey.NAME, ClaimKey.EMAIL, ClaimKey.LEMONTAG],
  },
});

Returns

type AuthenticateResponse = {
  result: TransactionResult.SUCCESS;
  data: {
    wallet: string;
    grantedClaims: MiniAppGrantedClaim[];
    signature: string;
    message: string;
  };
} | {
  result: TransactionResult.FAILED;
  error: {
    message: string;
    code: string;
  };
} | {
  result: TransactionResult.CANCELLED;
};
result
TransactionResult
The result of the authentication attempt.
  • SUCCESS: The authentication was successful.
  • FAILED: The authentication failed.
  • CANCELLED: The authentication was cancelled by the user.
data
object
Contains the wallet address, granted claims, signature and message. Only present when the result is SUCCESS.
  • wallet: The wallet address of the authenticated user.
  • grantedClaims: An array of MiniAppGrantedClaim objects containing the claims granted by the user. Each object has a key (the ClaimKey) and a value (the claim’s value). This will contain the claims that were requested in the requirements.claims parameter, if provided.
  • signature: The cryptographic signature proving the user’s authentication.
  • message: The message that was signed by the user’s wallet.
error
object
Contains the error details when the authentication fails. Only present when the result is FAILED.
  • message: A human-readable error message describing what went wrong.
  • code: A machine-readable error code for programmatic error handling.

Complete Authentication Flow

Backend endpoints The backend is responsible for generating a nonce and verifying the signature.
import crypto from 'crypto';

// Generate a cryptographically secure nonce
async function generateNonce(): Promise<string> {
  // Generate 32 random bytes and convert to hex
  const nonce = crypto.randomBytes(32).toString('hex');
  
  // TODO: Store the nonce in your database with:
  // - timestamp for expiration
  // - used flag to prevent replay attacks
  // - user identifier
  
  return nonce;
}

app.post('/api/auth/nonce', async (req, res) => {
    const nonce = await generateNonce();
    res.json({ nonce });
});
Frontend React component:
import React, { useState, useEffect } from 'react';
import { authenticate, ChainId, TransactionResult } from '@lemoncash/mini-app-sdk';
import { getNonceFromBackend, verifySignatureOnBackend } from './api';

export const MiniApp: React.FC = () => {
  const [wallet, setWallet] = useState<string | undefined>(undefined);

  const handleAuthenticate = async () => {    
    // 1. Get a unique nonce from your backend
    const nonce = await getNonceFromBackend();
    
    // 2. Request the signature using the nonce
    const result = await authenticate({ 
      nonce, 
      chainId: ChainId.POLYGON_AMOY 
    });
    
    if (result.result === TransactionResult.FAILED) {
      throw new Error(`Authentication failed: ${result.error.message} (${result.error.code})`);
    }
    
    if (result.result === TransactionResult.CANCELLED) {
      throw new Error('Authentication was cancelled by the user');
    }
    
    const { wallet, signature, message } = result.data;
    
    // 3. Verify the signature on your backend
    const verificationResult = await verifySignatureOnBackend({
      wallet,
      signature,
      message,
      nonce,
    });
    
    if (verificationResult.verified) {
      setWallet(wallet);
    }
  };

  // Trigger authentication on component mount
  useEffect(() => {
    handleAuthenticate();
  }, []);

  return (
    <div>
      <h2>Wallet</h2>
      <p>
        Connected: {wallet ? '✅ Connected' : '❌ Not connected'}
      </p>
      
      {wallet && (
        <p>
          {wallet}
        </p>
      )}
    </div>
  );
};

ERC-6492 Support

The smart contract wallet is deployed on the first user’s transaction. The authenticate method supports ERC-6492 for contract wallets that are not yet deployed. This means users can authenticate even before their wallet contract is deployed.