# Authentication Flow

This example demonstrates a complete authentication flow with token management and error handling.

### React Component Example

```typescript
import { useState, useEffect } from "react";
import { YieldFiSDK, AuthenticationError, NetworkError } from "yieldfi-sdk";
import { ethers } from "ethers";

function AuthExample() {
  const [sdk, setSdk] = useState<YieldFiSDK | null>(null);
  const [user, setUser] = useState<any>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    initializeSDK();
    checkExistingAuth();
  }, []);

  const initializeSDK = async () => {
    try {
      const sdkInstance = await YieldFiSDK.create({
        gatewayUrl: "https://gw.yield.fi",
      });
      setSdk(sdkInstance);
    } catch (err: any) {
      setError(`Failed to initialize SDK: ${err.message}`);
    }
  };

  const checkExistingAuth = async () => {
    const accessToken = localStorage.getItem("accessToken");
    if (!accessToken || !sdk) return;

    try {
      // Verify token is still valid by making a test request
      const transactions = await sdk.vault.getTransactions(
        { chainId: 1, page: 1, pageSize: 1 },
        accessToken
      );

      // Token is valid, load user info
      const userStr = localStorage.getItem("user");
      if (userStr) {
        setUser(JSON.parse(userStr));
      }
    } catch (err) {
      // Token expired or invalid, clear storage
      localStorage.removeItem("accessToken");
      localStorage.removeItem("refreshToken");
      localStorage.removeItem("user");
    }
  };

  const handleLogin = async () => {
    if (!sdk) {
      setError("SDK not initialized");
      return;
    }

    try {
      setLoading(true);
      setError(null);

      // 1. Connect to wallet
      if (!window.ethereum) {
        throw new Error("MetaMask not installed");
      }

      const provider = new ethers.BrowserProvider(window.ethereum);
      await provider.send("eth_requestAccounts", []);
      const signer = await provider.getSigner();
      const address = await signer.getAddress();

      // 2. Generate nonce
      const nonce = await sdk.auth.generateNonce({ address });

      // 3. Sign message
      const signature = await signer.signMessage(nonce.message);

      // 4. Login
      const authResponse = await sdk.auth.login({
        address,
        signature,
        message: nonce.message,
      });

      // 5. Store tokens and user info
      localStorage.setItem("accessToken", authResponse.accessToken);
      localStorage.setItem("refreshToken", authResponse.refreshToken);
      localStorage.setItem("user", JSON.stringify(authResponse.user));

      setUser(authResponse.user);
      console.log("Login successful!");
    } catch (err: any) {
      if (err instanceof AuthenticationError) {
        setError(`Authentication failed: ${err.message}`);
      } else if (err instanceof NetworkError) {
        setError(`Network error: ${err.message}`);
      } else {
        setError(`Login failed: ${err.message}`);
      }
    } finally {
      setLoading(false);
    }
  };

  const handleLogout = async () => {
    if (!sdk) return;

    try {
      const accessToken = localStorage.getItem("accessToken");
      if (accessToken) {
        await sdk.auth.logout(accessToken);
      }
    } catch (err) {
      console.error("Logout error:", err);
    } finally {
      localStorage.removeItem("accessToken");
      localStorage.removeItem("refreshToken");
      localStorage.removeItem("user");
      setUser(null);
    }
  };

  if (!sdk) {
    return <div>Initializing SDK...</div>;
  }

  return (
    <div>
      {user ? (
        <div>
          <p>Logged in as: {user.address}</p>
          <p>Role: {user.role}</p>
          <button onClick={handleLogout}>Logout</button>
        </div>
      ) : (
        <div>
          <button onClick={handleLogin} disabled={loading}>
            {loading ? "Connecting..." : "Connect Wallet"}
          </button>
          {error && <p style={{ color: "red" }}>{error}</p>}
        </div>
      )}
    </div>
  );
}

export default AuthExample;
```

### Token Refresh Utility

```typescript
import { YieldFiSDK, isTokenExpired } from "yieldfi-sdk";

async function getValidAccessToken(): Promise<string | null> {
  let accessToken = localStorage.getItem("accessToken");
  const refreshToken = localStorage.getItem("refreshToken");

  // Check if token is expired or expiring soon (5 minute buffer)
  if (!accessToken || isTokenExpired(accessToken, 300)) {
    if (!refreshToken) {
      return null;
    }

    try {
      const sdk = await YieldFiSDK.create({
        gatewayUrl: "https://gw.yield.fi",
      });

      const newTokens = await sdk.auth.refresh({ refreshToken });
      accessToken = newTokens.accessToken;

      localStorage.setItem("accessToken", newTokens.accessToken);
      localStorage.setItem("refreshToken", newTokens.refreshToken);

      return accessToken;
    } catch (error) {
      localStorage.removeItem("accessToken");
      localStorage.removeItem("refreshToken");
      return null;
    }
  }

  return accessToken;
}
```

### Usage in API Calls

```typescript
async function fetchUserTransactions() {
  const accessToken = await getValidAccessToken();
  
  if (!accessToken) {
    // Redirect to login
    window.location.href = "/login";
    return;
  }

  try {
    const transactions = await sdk.vault.getTransactions(
      { chainId: 1, page: 1, pageSize: 20 },
      accessToken
    );
    return transactions;
  } catch (error) {
    if (error instanceof AuthenticationError) {
      // Token invalid, clear and redirect
      localStorage.clear();
      window.location.href = "/login";
    }
    throw error;
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.yield.fi/earn-with-yieldfi/integration-sdk/examples-and-guides/authentication-flow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
