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

# React Authentication

> Using accessToken for secure API requests in React applications

## Overview

When embedding Flatfile in React applications, it's important to understand the proper authentication flow for making API requests. The `publishableKey` is designed exclusively for initializing the `FlatfileProvider` component, while the `accessToken` should be used for all subsequent API requests.

## Security Best Practice

The `publishableKey` is restricted to its intended use: initializing the Flatfile embedded experience. For security reasons, it cannot be used to make API requests directly. Instead, use the `accessToken` that becomes available after the Space is created.

## Accessing the Access Token

Use the `useFlatfileInternal` hook to access the `accessToken` and `sessionSpace` after initialization:

```jsx theme={null}
import { useFlatfileInternal } from "@flatfile/react";

const MyComponent = () => {
  const { accessToken, sessionSpace } = useFlatfileInternal();
  
  // accessToken is available after the space is created
  console.log("Access Token:", accessToken);
  console.log("Session Space:", sessionSpace);
  
  return <div>...</div>;
};
```

<Note>
  The `accessToken` will be `undefined` until the space is actually created (after `openPortal()` is called and the space is initialized). Always check for its availability before making API calls.
</Note>

## Making API Requests

### Basic Pattern

Here's the recommended pattern for making API requests using the `accessToken`:

```jsx theme={null}
import { useEffect, useState } from "react";
import { useFlatfileInternal } from "@flatfile/react";
import { FlatfileClient } from "@flatfile/api";

const MyComponent = () => {
  const { accessToken, sessionSpace } = useFlatfileInternal();
  const [data, setData] = useState([]);

  useEffect(() => {
    // Wait for the space to be created and token to be available
    if (!accessToken || !sessionSpace?.id) return;

    // Initialize the API client with the accessToken
    const api = new FlatfileClient({ token: accessToken });

    const fetchData = async () => {
      try {
        // Make API requests using the authenticated client
        const workbooks = await api.workbooks.list({ 
          spaceId: sessionSpace.id 
        });
        setData(workbooks.data);
      } catch (error) {
        console.error("API Error:", error);
      }
    };

    fetchData();
  }, [accessToken, sessionSpace?.id]);

  return <div>{data.length} workbooks found</div>;
};
```

### Complete Example

Here's a complete example showing how to set up authentication and make API requests:

```jsx theme={null}
import { useState, useEffect } from "react";
import { 
  FlatfileProvider, 
  useFlatfile, 
  useFlatfileInternal,
  Space,
  Workbook 
} from "@flatfile/react";
import { FlatfileClient } from "@flatfile/api";

// Main App component
export const App = ({ publishableKey }) => (
  <FlatfileProvider publishableKey={publishableKey}>
    <SpaceWithApiAccess />
  </FlatfileProvider>
);

// Component that accesses the API
const SpaceWithApiAccess = () => {
  const { openPortal } = useFlatfile();
  const { accessToken, sessionSpace } = useFlatfileInternal();
  const [records, setRecords] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!accessToken || !sessionSpace?.id) return;

    // Initialize the API client with the accessToken
    const api = new FlatfileClient({ token: accessToken });

    const fetchData = async () => {
      setLoading(true);
      try {
        // Example: Get all workbooks in the space
        const workbooks = await api.workbooks.list({ 
          spaceId: sessionSpace.id 
        });
        console.log("Workbooks:", workbooks.data);

        // Example: Get sheets from the first workbook
        if (workbooks.data?.[0]?.id) {
          const sheets = await api.sheets.list({ 
            workbookId: workbooks.data[0].id 
          });
          
          // Example: Get records from the first sheet
          if (sheets.data?.[0]?.id) {
            const sheetRecords = await api.records.get(sheets.data[0].id);
            setRecords(sheetRecords.data?.records || []);
          }
        }

        // Example: Get space details
        const space = await api.spaces.get(sessionSpace.id);
        console.log("Space details:", space.data);
      } catch (error) {
        console.error("API Error:", error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [accessToken, sessionSpace?.id]);

  return (
    <div>
      <button onClick={() => openPortal()}>
        Open Flatfile
      </button>
      
      {loading && <p>Loading...</p>}
      
      {records.length > 0 && (
        <div>
          <h2>Records</h2>
          <p>Fetched {records.length} records from the space</p>
        </div>
      )}
      
      <Space config={{ name: "My Space" }}>
        <Workbook 
          config={{ 
            name: "My Workbook", 
            sheets: [
              {
                name: "Contacts",
                slug: "contacts",
                fields: [
                  { key: "name", type: "string", label: "Name" },
                  { key: "email", type: "string", label: "Email" },
                ]
              }
            ]
          }} 
        />
      </Space>
    </div>
  );
};
```

## Common API Operations

Once you have the `accessToken`, you can perform various operations:

```javascript theme={null}
const api = new FlatfileClient({ token: accessToken });

// Spaces
await api.spaces.get(spaceId);
await api.spaces.update(spaceId, { name: "New Name" });

// Workbooks
await api.workbooks.list({ spaceId });
await api.workbooks.get(workbookId);

// Sheets
await api.sheets.list({ workbookId });
await api.sheets.get(sheetId);

// Records
await api.records.get(sheetId);
await api.records.insert(sheetId, [
  { firstName: "John", lastName: "Doe" }
]);
await api.records.update(sheetId, { records: [...] });
await api.records.delete(sheetId, { ids: ["rec_123"] });

// Files
await api.files.list({ spaceId });
await api.files.get(fileId);

// Jobs
await api.jobs.list({ spaceId });
await api.jobs.get(jobId);

// Documents
await api.documents.list(spaceId);
await api.documents.create(spaceId, { 
  title: "Guide", 
  body: "# Welcome" 
});
```

## Handling User Actions

For API calls triggered by user actions, ensure the token is available:

```jsx theme={null}
const MyComponent = () => {
  const { accessToken, sessionSpace } = useFlatfileInternal();
  
  const handleFetchRecords = async () => {
    if (!accessToken) {
      console.error("Space not initialized yet");
      return;
    }
    
    const api = new FlatfileClient({ token: accessToken });
    const records = await api.records.get(sheetId);
    console.log(records);
  };
  
  return (
    <button onClick={handleFetchRecords}>
      Fetch Records
    </button>
  );
};
```

## Creating a Custom Hook

For cleaner code, create a custom hook for API access:

```jsx theme={null}
import { useMemo } from "react";
import { useFlatfileInternal } from "@flatfile/react";
import { FlatfileClient } from "@flatfile/api";

const useFlatfileAPI = () => {
  const { accessToken, sessionSpace } = useFlatfileInternal();
  
  const api = useMemo(() => {
    if (!accessToken) return null;
    return new FlatfileClient({ token: accessToken });
  }, [accessToken]);
  
  return { api, sessionSpace, isReady: !!api };
};

// Usage
const MyComponent = () => {
  const { api, sessionSpace, isReady } = useFlatfileAPI();
  
  useEffect(() => {
    if (!isReady) return;
    
    const fetchData = async () => {
      const workbooks = await api.workbooks.list({ 
        spaceId: sessionSpace.id 
      });
      console.log(workbooks);
    };
    
    fetchData();
  }, [isReady, api, sessionSpace]);
  
  return <div>...</div>;
};
```

## Troubleshooting

### "accessToken is undefined"

**Cause:** The space hasn't been created yet.

**Solution:** Add null checks and wait for the token:

```jsx theme={null}
useEffect(() => {
  if (!accessToken) {
    console.log("Waiting for space to be created...");
    return;
  }
  
  // Token is now available
}, [accessToken]);
```

### "Cannot read property 'id' of undefined"

**Cause:** Trying to access `sessionSpace.id` before the space is created.

**Solution:** Check both `accessToken` and `sessionSpace`:

```jsx theme={null}
if (!accessToken || !sessionSpace?.id) return;
```

## Key Differences

| Hook                  | Exposes                                                                                      |
| --------------------- | -------------------------------------------------------------------------------------------- |
| `useFlatfile`         | `openPortal`, `closePortal`, `open`, `setListener`, `listener`                               |
| `useFlatfileInternal` | All of the above **PLUS** `accessToken`, `setAccessToken`, `sessionSpace`, `setSessionSpace` |

## Summary

**Three key steps for secure API requests:**

1. Use `publishableKey` only for `FlatfileProvider` initialization
2. Access `accessToken` via `useFlatfileInternal` hook
3. Initialize `FlatfileClient` with the `accessToken` for all API requests

This pattern ensures your API calls are properly authenticated and scoped to the correct space.

## Next Steps

* [API Reference](https://reference.flatfile.com) - Complete API documentation
* [Advanced Configuration](/embedding/advanced-configuration) - Authentication options
* [Server Setup](/embedding/server-setup) - Backend integration patterns
