npm package: @optare/optareid-react
Description: React Hooks and Components for Optare ID
Author: Optare Team
Latest version: 0.1.10

# @optare/optareid-react

React hooks and components for [Optare ID](https://id.optare.one) authentication.

## Installation

```bash
npm install @optare/optareid-react
# or
yarn add @optare/optareid-react
# or
pnpm add @optare/optareid-react
```

## Quick Start

### 1. Wrap your app with OptareProvider

```tsx
// src/main.tsx
import { OptareProvider } from '@optare/optareid-react';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <OptareProvider
      domain="https://id.optare.one"
      clientId={import.meta.env.VITE_OPTARE_CLIENT_ID}
      redirectUri={window.location.origin}
    >
      <App />
    </OptareProvider>
  </React.StrictMode>
);
```

### 2. Use the hook in your components

```tsx
import { useOptare, SignInButton, LogoutButton } from '@optare/optareid-react';

function App() {
  const { isAuthenticated, isLoading, user, error } = useOptare();

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      {isAuthenticated ? (
        <>
          <h1>Welcome, {user?.name}!</h1>
          <LogoutButton />
        </>
      ) : (
        <SignInButton />
      )}
    </div>
  );
}
```

## API Reference

### OptareProvider Props

| Prop | Type | Description |
|------|------|-------------|
| `domain` | `string` | Optare ID domain (default: `https://id.optare.one`) |
| `clientId` | `string` | Your OAuth Client ID |
| `redirectUri` | `string` | OAuth callback URL (default: `window.location.origin`) |
| `scopes` | `string[]` | OAuth scopes (default: `['openid', 'profile', 'email']`) |
| `audience` | `string` | API audience for token requests |
| `onAuthComplete` | `(user: User) => void` | Called when authentication completes |
| `onError` | `(error: Error) => void` | Called when an error occurs |
| `onRedirectCallback` | `(appState?) => void` | Called after OAuth redirect |

### useOptare() Hook

```typescript
const {
  client,              // OptareClient instance
  user,                // User object
  isAuthenticated,     // boolean
  isLoading,          // boolean
  error,              // Error | null
  login,              // (options?) => void
  logout,             // (options?) => Promise<void>
  getAccessToken,     // () => Promise<string | null>
  getAccessTokenSilently, // (options?) => Promise<string>
} = useOptare();
```

---

## Components

### SignInButton

```tsx
import { SignInButton } from '@optare/optareid-react';

<SignInButton label="Sign in" />
```

### LogoutButton

```tsx
import { LogoutButton } from '@optare/optareid-react';

<LogoutButton label="Log out" returnTo="/" />
```

### ProtectedRoute

Protects children, redirecting to login if not authenticated.

```tsx
import { ProtectedRoute } from '@optare/optareid-react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/dashboard" element={
    <ProtectedRoute>
      <Dashboard />
    </ProtectedRoute>
  } />
</Routes>
```

**Props:**
- `loadingComponent` - Custom loading component
- `redirectingComponent` - Custom redirecting component  
- `fallback` - Show instead of redirecting (for conditional rendering)
- `returnTo` - URL to return to after login

---

## Advanced Usage

### Protecting Routes with React Router

```tsx
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { useOptare, ProtectedRoute } from '@optare/optareid-react';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/profile" element={
          <ProtectedRoute>
            <Profile />
          </ProtectedRoute>
        } />
        <Route path="/dashboard" element={
          <ProtectedRoute 
            loadingComponent={<p>Checking authentication...</p>}
          >
            <Dashboard />
          </ProtectedRoute>
        } />
      </Routes>
    </BrowserRouter>
  );
}
```

### Calling Protected APIs

```tsx
import { useOptare } from '@optare/optareid-react';

function ApiCall() {
  const { getAccessTokenSilently } = useOptare();
  const [data, setData] = useState(null);

  const callProtectedApi = async () => {
    try {
      const token = await getAccessTokenSilently();
      
      const response = await fetch('/api/protected', {
        headers: {
          Authorization: `Bearer ${token}`
        }
      });
      
      const result = await response.json();
      setData(result);
    } catch (error) {
      console.error('API call failed:', error);
    }
  };

  return (
    <div>
      <button onClick={callProtectedApi}>Call API</button>
      {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
    </div>
  );
}
```

### Using Higher-Order Components

```tsx
import { withAuthenticationRequired } from '@optare/optareid-react';

function Dashboard() {
  return <div>Protected Dashboard Content</div>;
}

// Wrap component to require authentication
const ProtectedDashboard = withAuthenticationRequired(Dashboard, {
  onLoading: () => <p>Loading...</p>,
  onRedirecting: () => <p>Redirecting to login...</p>,
  returnTo: '/dashboard'
});

export default ProtectedDashboard;
```

### Custom useAuthenticatedUser Hook

```tsx
import { useAuthenticatedUser } from '@optare/optareid-react';

function UserDashboard() {
  const { user, accessToken, isLoading } = useAuthenticatedUser();

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Welcome, {user?.name}</h1>
      <p>Token: {accessToken ? 'Available' : 'Not available'}</p>
    </div>
  );
}
```

### Using fetchWithAuth Utility

```tsx
import { useOptare, fetchWithAuth } from '@optare/optareid-react';

function DataFetcher() {
  const { getAccessTokenSilently } = useOptare();
  
  const loadData = async () => {
    const response = await fetchWithAuth(
      '/api/data',
      { method: 'GET' },
      getAccessTokenSilently
    );
    return response.json();
  };
}
```

---

## Environment Variables

```env
# Required
VITE_OPTARE_CLIENT_ID=your_client_id

# Optional
VITE_OPTARE_DOMAIN=https://id.optare.one
```

## CLI Setup (Recommended)

```bash
# Install Optare CLI
npm install -g @optare/optareid-cli

# Login and initialize project
optare login
optare init
```

This automatically:
- Creates an OAuth client
- Configures redirect URLs
- Generates your `.env` file

## Browser Support

- Chrome/Edge 90+
- Firefox 88+
- Safari 14+

## AI Integration

See [AI_PROMPT.md](./AI_PROMPT.md) for an AI-friendly prompt to integrate Optare in your IDE.

## Documentation

- [Full Documentation](https://docs.optare.one)
- [API Reference](https://docs.optare.one/api)

## Support

- **Issues:** [GitHub Issues](https://github.com/optare/optare-on/issues)
- **Email:** support@optare.one

## License

MIT