# useOAuth & usePasskey

雖然 `DidConnect` 元件和 `useConnect` hook 為所有驗證方法提供了一套全面、預先建置好的 UI，但您可能需要建置自訂的驗證流程。`useOAuth` 和 `usePasskey` hook 提供了直接存取社交登入（OAuth）和無密碼驗證（Passkey）底層邏輯的方法。

這些 hook 是建立客製化使用者體驗的強大工具。它們依賴於各自的 context provider，即 `OAuthProvider` 和 `PasskeyProvider`，而這些 provider 通常包含在主 `SessionProvider` 中。有關 session 管理的更多資訊，請參閱 [SessionProvider 文件](./core-components-session-provider.md)。

## useOAuth

`useOAuth` hook 提供了用於處理第三方社交登入流程的函式和狀態。

### 匯入

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

### 返回值

此 hook 會返回一個包含以下屬性和方法的物件：

<x-field-group>
  <x-field data-name="loginOAuth" data-type="function" data-required="true">
    <x-field-desc markdown>使用指定的 OAuth provider 啟動登入流程。它會開啟一個彈出視窗供使用者授權，並返回一個 promise，該 promise 會解析為登入結果。</x-field-desc>
  </x-field>
  <x-field data-name="bindOAuth" data-type="function" data-required="true">
    <x-field-desc markdown>將新的 OAuth 帳號綁定到目前登入使用者的 session。</x-field-desc>
  </x-field>
  <x-field data-name="unbindOAuth" data-type="function" data-required="true">
    <x-field-desc markdown>從目前使用者的 session 解除綁定一個 OAuth 帳號。</x-field-desc>
  </x-field>
  <x-field data-name="getOAuthConfigList" data-type="function" data-required="true">
    <x-field-desc markdown>從 blocklet 設定中取得已啟用和已設定的 OAuth provider 列表。返回一個 promise，該 promise 會解析為一個 provider 設定物件的陣列。</x-field-desc>
  </x-field>
  <x-field data-name="switchOAuthPassport" data-type="function" data-required="true">
    <x-field-desc markdown>啟動一個流程，以在相同身分的不同已連接帳號（passports）之間切換。</x-field-desc>
  </x-field>
  <x-field data-name="bindAuthLoading" data-type="boolean" data-required="true">
    <x-field-desc markdown>一個布林值標誌，在 `bindOAuth` 操作進行中時為 `true`。</x-field-desc>
  </x-field>
  <x-field data-name="unbindAuthLoading" data-type="boolean" data-required="true">
    <x-field-desc markdown>一個布林值標誌，在 `unbindOAuth` 操作進行中時為 `true`。</x-field-desc>
  </x-field>
  <x-field data-name="oauthState" data-type="object" data-required="true">
    <x-field-desc markdown>一個包含驗證過程即時狀態的物件。</x-field-desc>
    <x-field data-name="loading" data-type="boolean" data-desc="如果 OAuth 操作正在進行中，則為 True。"></x-field>
    <x-field data-name="error" data-type="string" data-desc="如果操作失敗，則包含錯誤訊息。"></x-field>
    <x-field data-name="status" data-type="string" data-desc="流程的目前狀態（例如 'scanned', 'succeed', 'error'）。"></x-field>
  </x-field>
</x-field-group>

### 使用範例

這是一個如何建置自訂社交登入元件的範例。

```jsx CustomSocialLogin.jsx icon=logos:react
import React, { useEffect, useState } from 'react';
import { useOAuth } from '@arcblock/did-connect-react/lib/OAuth';
import { useSession } from '@arcblock/did-connect-react/lib/Session';

export default function CustomSocialLogin() {
  const { loginOAuth, getOAuthConfigList } = useOAuth();
  const { session } = useSession();
  const [providers, setProviders] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  useEffect(() => {
    // 當元件掛載時，取得可用的 OAuth provider 列表
    getOAuthConfigList().then(setProviders).catch(console.error);
  }, [getOAuthConfigList]);

  const handleLogin = async (provider) => {
    setLoading(true);
    setError('');
    try {
      const result = await loginOAuth({ provider: provider.provider });
      // 成功登入後，SessionProvider 會自動更新 session。
      console.log('Login successful:', result);
      // 您可能需要在此處重新整理 session 或重新導向使用者。
    } catch (err) {
      setError(err.message);
      console.error('Login failed:', err);
    } finally {
      setLoading(false);
    }
  };

  if (session.user) {
    return <div>You are already logged in as {session.user.name}.</div>;
  }

  if (providers.length === 0) {
    return <div>No social login methods configured.</div>;
  }

  return (
    <div>
      <h3>Login with Social Media</h3>
      {providers.map((p) => (
        <button key={p.provider} onClick={() => handleLogin(p)} disabled={loading}>
          {loading ? 'Logging in...' : `Login with ${p.provider}`}
        </button>
      ))}
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  );
}
```

## usePasskey

`usePasskey` hook 提供了使用 WebAuthn（Passkeys）處理無密碼驗證的函式和狀態。

### 匯入

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

### 返回值

此 hook 會返回一個包含以下屬性和方法的物件：

<x-field-group>
  <x-field data-name="loginPasskey" data-type="function" data-required="true">
    <x-field-desc markdown>使用現有的 Passkey 啟動登入流程。它會觸發瀏覽器原生的 WebAuthn 驗證提示。</x-field-desc>
  </x-field>
  <x-field data-name="connectPasskey" data-type="function" data-required="true">
    <x-field-desc markdown>啟動一個流程，以建立並將新的 Passkey 綁定到目前使用者的 session。</x-field-desc>
  </x-field>
  <x-field data-name="disconnectPasskey" data-type="function" data-required="true">
    <x-field-desc markdown>成功驗證後，從目前使用者的 session 解除綁定 Passkey。</x-field-desc>
  </x-field>
  <x-field data-name="switchPassport" data-type="function" data-required="true">
    <x-field-desc markdown>啟動一個流程，以在不同的已連接帳號（passports）之間切換。</x-field-desc>
  </x-field>
  <x-field data-name="connecting" data-type="boolean" data-required="true">
    <x-field-desc markdown>一個布林值標誌，在 `connectPasskey` 操作進行中時為 `true`。</x-field-desc>
  </x-field>
  <x-field data-name="disconnecting" data-type="boolean" data-required="true">
    <x-field-desc markdown>一個布林值標誌，在 `disconnectPasskey` 操作進行中時為 `true`。</x-field-desc>
  </x-field>
  <x-field data-name="passkeyState" data-type="object" data-required="true">
    <x-field-desc markdown>一個包含 Passkey 操作即時狀態的物件。</x-field-desc>
    <x-field data-name="loading" data-type="boolean" data-desc="如果 Passkey 操作正在進行中，則為 True。"></x-field>
    <x-field data-name="creating" data-type="boolean" data-desc="在 Passkey 建立階段為 True。"></x-field>
    <x-field data-name="verifying" data-type="boolean" data-desc="在 Passkey 驗證階段為 True。"></x-field>
    <x-field data-name="error" data-type="string" data-desc="如果操作失敗，則包含錯誤訊息。"></x-field>
    <x-field data-name="status" data-type="string" data-desc="流程的目前狀態（例如 'scanned', 'succeed', 'error'）。"></x-field>
  </x-field>
</x-field-group>

### 使用範例

這是一個如何建立「使用 Passkey 登入」按鈕的範例。

```jsx PasskeyLoginButton.jsx icon=logos:react
import React, { useState } from 'react';
import { usePasskey } from '@arcblock/did-connect-react/lib/Passkey';

export default function PasskeyLoginButton() {
  const { loginPasskey, passkeyState } = usePasskey();
  const [error, setError] = useState('');

  const handleLogin = async () => {
    setError('');
    try {
      const result = await loginPasskey();
      console.log('Passkey login successful:', result);
      // SessionProvider 會自動更新 session。
    } catch (err) {
      setError(err.message);
      console.error('Passkey login failed:', err);
    }
  };

  return (
    <div>
      <button onClick={handleLogin} disabled={passkeyState.loading}>
        {passkeyState.loading ? 'Verifying...' : 'Login with Passkey'}
      </button>
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  );
}
```

這些 hook 提供了將 DID Connect 強大的驗證功能整合到您應用程式的任何部分，並使用完全自訂 UI 的靈活性。要了解如何以程式化方式控制預先建置的 `DidConnect` 互動視窗，請繼續閱讀 [useConnect hook 文件](./hooks-use-connect.md)。