# Authentication Methods

While DID Wallet is the primary and most secure method for authentication, `@arcblock/did-connect-react` provides robust support for several alternative login methods to offer flexibility and cater to diverse user preferences. This section details how to integrate OAuth (social logins), Passkeys (passwordless authentication), and Federated Login into your application.

These methods are enabled through specific React Context Providers and accessed via corresponding hooks, which should be nested within the main `SessionProvider`.

---

## OAuth (Social Login)

Integrate popular social login providers like Google, GitHub, or Apple to allow users to sign in with their existing accounts. This functionality is managed by `OAuthProvider` and the `useOAuth` hook.

### 1. Setup with `OAuthProvider`

To enable OAuth functionalities, wrap your component tree with `OAuthProvider`. It's common to place it inside the `SessionProvider`.

```jsx OAuthProvider Setup icon=logos:react
import { SessionProvider } from '@arcblock/did-connect-react';
import { OAuthProvider } from '@arcblock/did-connect-react/lib/OAuth';

function App() {
  return (
    <SessionProvider>
      <OAuthProvider
        onBindOAuth={(provider) => console.log(`${provider.provider} bound!`)}
        onUnbindOAuth={(account) => console.log(`${account.provider} unbound!`)}>
        {/* Your application components */}
      </OAuthProvider>
    </SessionProvider>
  );
}
```

**Props for `OAuthProvider`**

<x-field-group>
  <x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="The child components that will have access to the OAuth context."></x-field>
  <x-field data-name="locale" data-type="string" data-default="en" data-desc="The language for UI messages and toasts."></x-field>
  <x-field data-name="onBindOAuth" data-type="function" data-desc="Callback function triggered after a user successfully binds an OAuth account."></x-field>
  <x-field data-name="onUnbindOAuth" data-type="function" data-desc="Callback function triggered after a user successfully unbinds an OAuth account."></x-field>
  <x-field data-name="onSwitchPassport" data-type="function" data-desc="Callback function triggered after a user switches passports."></x-field>
  <x-field data-name="session" data-type="object" data-desc="The current user session object, required for passport switching UI."></x-field>
</x-field-group>

### 2. Usage with `useOAuth` Hook

The `useOAuth` hook provides functions to interact with the OAuth authentication flows.

```jsx useOAuth Hook icon=logos:react
import { useOAuth } from '@arcblock/did-connect-react/lib/OAuth';

function SocialLoginButtons() {
  const { loginOAuth, getOAuthConfigList, bindAuthLoading } = useOAuth();
  const [providers, setProviders] = React.useState([]);

  React.useEffect(() => {
    getOAuthConfigList().then(setProviders);
  }, [getOAuthConfigList]);

  const handleLogin = async (provider) => {
    try {
      const result = await loginOAuth({ provider: provider.provider });
      console.log('Login successful:', result);
      // Handle login result, e.g., update session
    } catch (error) {
      console.error('Login failed:', error.message);
    }
  };

  if (providers.length === 0) {
    return <p>No third-party login methods configured.</p>;
  }

  return (
    <div>
      {providers.map((p) => (
        <button key={p.provider} onClick={() => handleLogin(p)} disabled={bindAuthLoading}>
          Login with {p.provider}
        </button>
      ))}
    </div>
  );
}
```

### Core Functions

- **`loginOAuth({ provider }, { action, ... })`**: Initiates the login flow for a specific provider. A popup window will open for user authentication.
- **`bindOAuth({ session, oauthItem })`**: Binds a new social account to the currently logged-in user.
- **`unbindOAuth({ session, connectedAccount })`**: Unbinds a social account from the current user.
- **`getOAuthConfigList()`**: Asynchronously fetches the list of enabled OAuth providers configured in the Blocklet settings.
- **`switchOAuthPassport(user)`**: Opens a dialog to switch between different user accounts (passports) associated with the same OAuth identity.

---

## Passkeys (Passwordless)

Enable modern, secure, and passwordless authentication using Passkeys, which are based on the WebAuthn standard. This allows users to sign in with biometrics (fingerprint, face ID), a device PIN, or a security key.

### 1. Setup with `PasskeyProvider`

Wrap your application with `PasskeyProvider` to enable Passkey functionality.

```jsx PasskeyProvider Setup icon=logos:react
import { SessionProvider } from '@arcblock/did-connect-react';
import { PasskeyProvider } from '@arcblock/did-connect-react/lib/Passkey';

function App() {
  return (
    <SessionProvider>
      <PasskeyProvider
        onAddPasskey={(result) => console.log('Passkey added!', result)}
        onRemovePasskey={(result) => console.log('Passkey removed!', result)}>
        {/* Your application components */}
      </PasskeyProvider>
    </SessionProvider>
  );
}
```

**Props for `PasskeyProvider`**

<x-field-group>
  <x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="The child components that will have access to the Passkey context."></x-field>
  <x-field data-name="locale" data-type="string" data-default="en" data-desc="The language for UI messages and toasts."></x-field>
  <x-field data-name="onAddPasskey" data-type="function" data-desc="Callback function triggered after a user successfully adds a Passkey."></x-field>
  <x-field data-name="onRemovePasskey" data-type="function" data-desc="Callback function triggered after a user successfully removes a Passkey."></x-field>
  <x-field data-name="onSwitchPassport" data-type="function" data-desc="Callback function triggered after a user switches passports."></x-field>
  <x-field data-name="session" data-type="object" data-desc="The current user session object, required for passport switching UI."></x-field>
</x-field-group>

### 2. Usage with `usePasskey` Hook

The `usePasskey` hook provides all the necessary functions for Passkey registration and authentication.

```jsx usePasskey Hook icon=logos:react
import { usePasskey } from '@arcblock/did-connect-react/lib/Passkey';
import { useSession } from '@arcblock/did-connect-react';

function PasskeyAuth() {
  const { loginPasskey, connectPasskey, connecting } = usePasskey();
  const { session } = useSession();

  const handleLogin = async () => {
    try {
      const result = await loginPasskey();
      console.log('Passkey login successful:', result);
      // Handle login result
    } catch (error) {
      console.error('Passkey login failed:', error.message);
    }
  };

  const handleConnect = async () => {
    // This should be called when a user is already logged in
    // and wants to add a passkey in their profile settings.
    if (!session.user) {
      alert('You must be logged in to add a passkey.');
      return;
    }
    try {
      await connectPasskey();
    } catch (error) {
      console.error('Failed to connect passkey:', error.message);
    }
  };

  return (
    <div>
      <button onClick={handleLogin}>Login with Passkey</button>
      {session.user && (
        <button onClick={handleConnect} disabled={connecting}>
          {connecting ? 'Connecting...' : 'Add a Passkey'}
        </button>
      )}
    </div>
  );
}
```

### Core Functions
- **`loginPasskey({ action, ... })`**: Initiates the Passkey authentication flow (also known as assertion). This is used for logging in existing users.
- **`connectPasskey(extraParams)`**: A high-level function to create and bind a new Passkey to the current user's account. It handles the full registration ceremony.
- **`disconnectPasskey({ session, connectedAccount })`**: Removes a Passkey from the current user's account after successful verification.
- **`createPasskey(params)`**: The lower-level function that starts the WebAuthn registration process. `connectPasskey` uses this internally.
- **`verifyPasskey(params)`**: The lower-level function that starts the WebAuthn authentication process. `loginPasskey` and `disconnectPasskey` use this internally.
- **`switchPassport(user)`**: Opens a dialog to switch between different user accounts (passports) that might share Passkeys.

---

## Federated Login

Federated Login allows a group of associated Blocklet applications (a "Federated Login Group") to share a single login session. When a user logs into the designated "master" site, they can be automatically authenticated on any "member" sites without needing to log in again.

### 1. Concept and Setup

This feature relies on a master-member site configuration within your Blocklet's settings. The `FederatedProvider` component is required to handle the cross-domain communication needed for this to work in modern browsers, particularly for managing third-party cookie access.

Like other providers, `FederatedProvider` should be included in your component tree, typically within `SessionProvider`.

```jsx FederatedProvider Setup icon=logos:react
import { SessionProvider } from '@arcblock/did-connect-react';
import { FederatedProvider } from '@arcblock/did-connect-react/lib/Federated';

function App() {
  return (
    <SessionProvider>
      <FederatedProvider>
        {/* Your application components */}
      </FederatedProvider>
    </SessionProvider>
  );
}
```

### 2. Usage

Federated login logic is integrated directly into the session management. You can trigger it using the `loginFederated` function available on the `session` object returned by `useSession`.

`loginFederated` supports two modes:
- **`auto`**: Attempts to silently log the user in if they have an active session on the master site. This is ideal for checking on page load.
- **`manual`**: Initiates a standard DID Connect login flow. Upon successful login, it also establishes the federated session with the master site.

```jsx Federated Login Example icon=logos:react
import { useSession } from '@arcblock/did-connect-react';
import React from 'react';

function FederatedLogin() {
  const { session } = useSession();
  const { federatedEnabled, loginFederated } = session;

  // Attempt auto-login on component mount
  React.useEffect(() => {
    if (federatedEnabled) {
      loginFederated((err) => {
        if (err) {
          console.warn('Auto federated login failed:', err);
        } else {
          console.log('Auto federated login successful!');
        }
      }, { mode: 'auto' });
    }
  }, [federatedEnabled, loginFederated]);

  const handleManualLogin = () => {
    loginFederated((err) => {
      if (err) console.error('Manual federated login failed:', err);
    }, { mode: 'manual' });
  };

  if (!federatedEnabled) {
    return <p>Federated login is not enabled.</p>;
  }

  return (
    <button onClick={handleManualLogin}>
      Login with Master Site Account
    </button>
  );
}
```