> ## Documentation Index
> Fetch the complete documentation index at: https://lemoncash.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticate

> Authenticate a user using Sign In With Ethereum (SIWE).

The `authenticate` function initiates the full onboarding flow between your Mini App and the Lemon Cash app. It presents the user with your Mini App's **Terms & Conditions**, **Privacy Policy**, and any **claim or permission requests** you specify. Once accepted, it authenticates the user using [Sign In With Ethereum (SIWE)](https://eips.ethereum.org/EIPS/eip-4361) and returns the user's wallet address, granted claims, and a signed message that verifies wallet ownership.

## Important Guidelines

<Note>
  Your Mini App must follow these rules to be approved for publication.
</Note>

* **Call `authenticate` as soon as the user enters your Mini App.** It must be invoked before any other function (`deposit`, `withdraw`, `callSmartContract`, etc.). During this step, users are presented with the Terms & Conditions, Privacy Policy, and claim permissions.
* **Use `authenticate` as your login flow.** It is the only supported authentication method. If you need the user's email or other data, request it as a [claim](/types/types#claim-keys) via `requirements.claims`.
* **Call `authenticate` on every entry.** Invoke it each time a user opens your Mini App to ensure the wallet address is always fresh. If your app supports multiple chains, re-trigger `authenticate` when the user switches chains.

## Usage

```typescript wrap theme={null}
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

```typescript theme={null}
type AuthenticateData = {
  nonce?: string;
  chainId: ChainId;
  requirements?: {
    claims?: ClaimKey[];
  };
}
```

<ParamField body="nonce" type="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.
</ParamField>

```typescript wrap focus={2-3} theme={null}
await authenticate({
  nonce: 'l3m0nc45h',
  chainId: ChainId.POLYGON_AMOY,
});
```

<ParamField body="chainId" type="ChainId" required>
  The chain id to use for the authentication request. This parameter is required.
</ParamField>

```typescript wrap focus={4} theme={null}
import { ChainId } from '@lemoncash/mini-app-sdk';

await authenticate({
  chainId: ChainId.POLYGON_AMOY,
});
```

<ParamField body="requirements" type="object">
  Optional requirements for the authentication request.
</ParamField>

<ParamField body="requirements.claims" type="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](/types/types) for the complete list of available claim keys.
</ParamField>

```typescript wrap focus={4-6} theme={null}
import { authenticate, ChainId, ClaimKey } from '@lemoncash/mini-app-sdk';

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

## Returns

<CodeGroup>
  ```typescript AuthenticateResponse theme={null}
  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;
  };
  ```

  ```typescript SUCCESS icon="check" theme={null}
  {
      result: 'SUCCESS',
      data: {
        wallet: '0x1Ed17b06961B9B8DE78Ee924BcDaBC003aaE1867',
        grantedClaims: [
          { key: 'NAME', value: 'John' },
          { key: 'EMAIL', value: 'john@example.com' },
          { key: 'LEMONTAG', value: 'johndoe' }
        ],
        signature: '0xba099e3ab31b8bf1201d2de2d0e4d81f7162f5de6993a960988959ff97be45b27d284a6e29d065cd175122953cf861725906639dc1f3229e66ff8b9d5820634a1b',
        message: 'web3-miniapps-svc.svc.staging.lemon wants you to sign in with your Ethereum account:\n0x1Ed17b06961B9B8DE78Ee924BcDaBC003aaE1867\n\nSign in with Ethereum to the app cbbe623b-be3d-4796-aa61-c93253a0a3af.\n\nURI: http://web3-miniapps-svc.svc.staging.lemon/auth/cbbe623b-be3d-4796-aa61-c93253a0a3af\nVersion: 1\nChain ID: 80002\nNonce: l3m0nc45h\nIssued At: 2025-09-03T19:02:52.697Z'
      }
  }
  ```

  ```typescript FAILED icon="ban" theme={null}
  {
      result: 'FAILED',
      error: {
        message: 'Invalid signature',
        code: 'INVALID_SIGNATURE'
      }
  }
  ```

  ```typescript CANCELLED icon="user-minus" theme={null}
  {
      result: 'CANCELLED',
  }
  ```
</CodeGroup>

<ResponseField name="result" type="TransactionResult">
  The result of the authentication attempt.

  * `SUCCESS`: The authentication was successful.
  * `FAILED`: The authentication failed.
  * `CANCELLED`: The authentication was cancelled by the user.
</ResponseField>

<ResponseField name="data" type="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.
</ResponseField>

<ResponseField name="error" type="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.
</ResponseField>

### Complete Authentication Flow

**Backend endpoints**

The backend is responsible for generating a nonce and verifying the signature.

<CodeGroup>
  ```typescript generateNonce.ts theme={null}
  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 });
  });
  ```

  ```typescript verifySiweSignature.ts theme={null}
  import { createPublicClient, http } from 'viem';
  import { mainnet } from 'viem/chains';

  // Create a public client for signature verification
  const publicClient = createPublicClient({
    chain: mainnet, // or your target chain
    transport: http()
  });

  async function verifySiweSignature(
    wallet: string, 
    signature: string, 
    message: string
  ): Promise<boolean> {
    try {
      // Before verification, check:
      // 1. Nonce exists in database and hasn't expired
      // 2. Nonce hasn't been used before
      // 3. Nonce matches the one in the signed message

      // Verify the SIWE signature (supports ERC-6492 for contract wallets)
      const isValid = await publicClient.verifySiweMessage({
        message: message,
        signature: signature as `0x${string}`,
        address: wallet as `0x${string}`,
      });
      
      if (isValid) {
        // After verification mark nonce as used in database
        return true;
      } else {
        return false;
      }
    } catch (error) {
      console.error('SIWE signature verification error:', error);
      return false;
    }
  }

  app.post('/api/auth/verify', async (req, res) => {
    try {
      const { wallet, signature, message, nonce } = req.body;
      
      const isValidSignature = await verifySiweSignature(wallet, signature, message);
      
      if (isValidSignature) {      
        res.json({ verified: true, wallet });
      } else {
        res.json({ verified: false, error: 'Invalid signature' });
      }
    } catch (error) {
      res.status(400).json({ error: error instanceof Error ? error.message : 'Verification failed' });
    }
  });
  ```
</CodeGroup>

**Frontend React component:**

<CodeGroup>
  ```typescript MiniApp.tsx theme={null}
  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>
    );
  };
  ```

  ```typescript api/getNonceFromBackend.ts theme={null}
  // API function to get nonce from backend
  export async function getNonceFromBackend(): Promise<string> {
    const response = await fetch('/api/auth/nonce', { method: 'POST' });
    
    if (!response.ok) {
      throw new Error('Failed to get nonce from backend');
    }
    
    const { nonce } = await response.json();
    return nonce;
  }
  ```

  ```typescript api/verifySignatureOnBackend.ts theme={null}
  // API function to verify signature on backend
  export async function verifySignatureOnBackend({
    wallet,
    signature,
    message,
    nonce,
  }: {
    wallet: string;
    signature: string;
    message: string;
    nonce: string;
  }) {
    const response = await fetch('/api/auth/verify', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        wallet,
        signature,
        message,
        nonce,
      }),
    });
    
    if (!response.ok) {
      throw new Error('Failed to verify signature');
    }
    
    return response.json();
  }
  ```
</CodeGroup>

### ERC-6492 Support

The smart contract wallet is deployed on the first user's transaction.

The `authenticate` method supports [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492) for contract wallets that are not yet deployed. This means users can authenticate even before their wallet contract is deployed.

## Related Functions

<CardGroup cols={2}>
  <Card title="deposit" icon="arrow-down-right" href="/functions/deposit">
    Deposit funds to your Mini App Wallet.
  </Card>

  <Card title="Call Smart Contract" icon="code" href="/functions/call-smart-contract">
    Interact with smart contracts on the blockchain.
  </Card>
</CardGroup>
