# 認証方法

DID Walletは主要かつ最も安全な認証方法ですが、`@arcblock/did-connect-react`は、柔軟性を提供し、多様なユーザーの好みに応えるために、いくつかの代替ログイン方法を強力にサポートしています。このセクションでは、OAuth（ソーシャルログイン）、パスキー（パスワードレス認証）、および統一ログインをアプリケーションに統合する方法について詳しく説明します。

これらの方法は、特定のReact Context Providerを介して有効になり、対応するフックを介してアクセスされます。これらはメインの`SessionProvider`内にネストする必要があります。

---

## OAuth（ソーシャルログイン）

Google、GitHub、Appleなどの人気のあるソーシャルログインプロバイダーを統合し、ユーザーが既存のアカウントでサインインできるようにします。この機能は`OAuthProvider`と`useOAuth`フックによって管理されます。

### 1. OAuthProviderでのセットアップ

OAuth機能を有効にするには、コンポーネントツリーを`OAuthProvider`でラップします。`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>
  );
}
```

**`OAuthProvider`のProps**

<x-field-group>
  <x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="OAuthコンテキストにアクセスできる子コンポーネント。"></x-field>
  <x-field data-name="locale" data-type="string" data-default="en" data-desc="UIメッセージとトーストの言語。"></x-field>
  <x-field data-name="onBindOAuth" data-type="function" data-desc="ユーザーがOAuthアカウントのバインドに成功した後にトリガーされるコールバック関数。"></x-field>
  <x-field data-name="onUnbindOAuth" data-type="function" data-desc="ユーザーがOAuthアカウントのバインド解除に成功した後にトリガーされるコールバック関数。"></x-field>
  <x-field data-name="onSwitchPassport" data-type="function" data-desc="ユーザーがパスポートを切り替えた後にトリガーされるコールバック関数。"></x-field>
  <x-field data-name="session" data-type="object" data-desc="現在のユーザーセッションオブジェクト。パスポート切り替えUIに必要です。"></x-field>
</x-field-group>

### 2. useOAuthフックの使用

`useOAuth`フックは、OAuth認証フローと対話するための関数を提供します。

```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);
      // ログイン結果を処理します（例：セッションの更新）
    } catch (error) {
      console.error('Login failed:', error.message);
    }
  };

  if (providers.length === 0) {
    return <p>設定されたサードパーティのログイン方法はありません。</p>;
  }

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

### コア関数

- **`loginOAuth({ provider }, { action, ... })`**: 特定のプロバイダーのログインフローを開始します。ユーザー認証のためにポップアップウィンドウが開きます。
- **`bindOAuth({ session, oauthItem })`**: 新しいソーシャルアカウントを現在ログインしているユーザーにバインドします。
- **`unbindOAuth({ session, connectedAccount })`**: 現在のユーザーからソーシャルアカウントのバインドを解除します。
- **`getOAuthConfigList()`**: Blockletの設定で構成された有効なOAuthプロバイダーのリストを非同期で取得します。
- **`switchOAuthPassport(user)`**: 同じOAuth IDに関連付けられた異なるユーザーアカウント（パスポート）を切り替えるためのダイアログを開きます。

---

## パスキー（パスワードレス）

WebAuthn標準に基づく最新で安全なパスワードレス認証であるパスキーを有効にします。これにより、ユーザーは生体認証（指紋、顔認証）、デバイスのPIN、またはセキュリティキーでサインインできます。

### 1. PasskeyProviderでのセットアップ

Passkey機能を有効にするには、アプリケーションを`PasskeyProvider`でラップします。

```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>
  );
}
```

**`PasskeyProvider`のProps**

<x-field-group>
  <x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="Passkeyコンテキストにアクセスできる子コンポーネント。"></x-field>
  <x-field data-name="locale" data-type="string" data-default="en" data-desc="UIメッセージとトーストの言語。"></x-field>
  <x-field data-name="onAddPasskey" data-type="function" data-desc="ユーザーがパスキーの追加に成功した後にトリガーされるコールバック関数。"></x-field>
  <x-field data-name="onRemovePasskey" data-type="function" data-desc="ユーザーがパスキーの削除に成功した後にトリガーされるコールバック関数。"></x-field>
  <x-field data-name="onSwitchPassport" data-type="function" data-desc="ユーザーがパスポートを切り替えた後にトリガーされるコールバック関数。"></x-field>
  <x-field data-name="session" data-type="object" data-desc="現在のユーザーセッションオブジェクト。パスポート切り替えUIに必要です。"></x-field>
</x-field-group>

### 2. usePasskeyフックの使用

`usePasskey`フックは、パスキーの登録と認証に必要なすべての関数を提供します。

```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);
      // ログイン結果を処理
    } catch (error) {
      console.error('Passkey login failed:', error.message);
    }
  };

  const handleConnect = async () => {
    // これはユーザーがすでにログインしている場合に呼び出されるべきです
    // そしてプロフィール設定でパスキーを追加したい場合。
    if (!session.user) {
      alert('パスキーを追加するにはログインする必要があります。');
      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>
  );
}
```

### コア関数
- **`loginPasskey({ action, ... })`**: パスキー認証フロー（アサーションとも呼ばれる）を開始します。これは既存のユーザーのログインに使用されます。
- **`connectPasskey(extraParams)`**: 新しいパスキーを作成し、現在のユーザーのアカウントにバインドするための高レベル関数です。完全な登録セレモニーを処理します。
- **`disconnectPasskey({ session, connectedAccount })`**: 検証が成功した後、現在のユーザーのアカウントからパスキーを削除します。
- **`createPasskey(params)`**: WebAuthn登録プロセスを開始する低レベル関数です。`connectPasskey`は内部でこれを使用します。
- **`verifyPasskey(params)`**: WebAuthn認証プロセスを開始する低レベル関数です。`loginPasskey`と`disconnectPasskey`は内部でこれを使用します。
- **`switchPassport(user)`**: パスキーを共有する可能性のある異なるユーザーアカウント（パスポート）を切り替えるためのダイアログを開きます。

---

## 統一ログイン

統一ログインは、関連するBlockletアプリケーションのグループ（「統一ログインサイト群」）が単一のログインセッションを共有できるようにします。ユーザーが指定された「マスター」サイトにログインすると、再度ログインする必要なく、どの「メンバー」サイトでも自動的に認証されます。

### 1. コンセプトとセットアップ

この機能は、Blockletの設定内のマスター-メンバーサイト構成に依存します。`FederatedProvider`コンポーネントは、特にサードパーティのクッキーアクセスを管理するために、最新のブラウザでこれが機能するために必要なクロスドメイン通信を処理するために必要です。

他のプロバイダーと同様に、`FederatedProvider`はコンポーネントツリーに含まれるべきであり、通常は`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. 使用方法

統一ログインロジックはセッション管理に直接統合されています。`useSession`が返す`session`オブジェクトで利用可能な`loginFederated`関数を使用してトリガーできます。

`loginFederated`は2つのモードをサポートしています：
- **`auto`**: マスターサイトでアクティブなセッションがある場合、ユーザーをサイレントにログインさせようとします。これはページロード時のチェックに最適です。
- **`manual`**: 標準のDID Connectログインフローを開始します。ログインに成功すると、マスターサイトとの統一セッションも確立します。

```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;

  // コンポーネントのマウント時に自動ログインを試行
  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>統一ログインは有効になっていません。</p>;
  }

  return (
    <button onClick={handleManualLogin}>
      マスターサイトのアカウントでログイン
    </button>
  );
}
```