# useOAuth & usePasskey

`DidConnect` 组件和 `useConnect` hook 为所有身份验证方法提供了全面的、预构建的用户界面，但你可能需要构建自定义的身份验证流程。`useOAuth` 和 `usePasskey` hook 提供了对社交登录 (OAuth) 和无密码身份验证 (Passkey) 底层逻辑的直接访问。

这些 hook 是创建定制化用户体验的强大工具。它们依赖于各自的上下文提供程序 `OAuthProvider` 和 `PasskeyProvider`，这些提供程序通常包含在主 `SessionProvider` 中。有关会话管理的更多信息，请参阅 [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 提供商启动登录流程。它会打开一个弹出窗口供用户授权，并返回一个解析为登录结果的 promise。</x-field-desc>
  </x-field>
  <x-field data-name="bindOAuth" data-type="function" data-required="true">
    <x-field-desc markdown>将新的 OAuth 帐户绑定到当前登录用户的会话。</x-field-desc>
  </x-field>
  <x-field data-name="unbindOAuth" data-type="function" data-required="true">
    <x-field-desc markdown>从当前用户的会话中解绑 OAuth 帐户。</x-field-desc>
  </x-field>
  <x-field data-name="getOAuthConfigList" data-type="function" data-required="true">
    <x-field-desc markdown>从 Blocklet 设置中获取已启用和已配置的 OAuth 提供商列表。返回一个解析为提供商配置对象数组的 promise。</x-field-desc>
  </x-field>
  <x-field data-name="switchOAuthPassport" data-type="function" data-required="true">
    <x-field-desc markdown>启动一个流程，用于在同一身份的不同已连接帐户（通行证）之间切换。</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 提供商列表
    getOAuthConfigList().then(setProviders).catch(console.error);
  }, [getOAuthConfigList]);

  const handleLogin = async (provider) => {
    setLoading(true);
    setError('');
    try {
      const result = await loginOAuth({ provider: provider.provider });
      // 成功登录后，会话将由 SessionProvider 自动更新。
      console.log('Login successful:', result);
      // 你可能需要在此处刷新会话或重定向用户。
    } catch (err) {
      setError(err.message);
      console.error('Login failed:', err);
    } finally {
      setLoading(false);
    }
  };

  if (session.user) {
    return <div>您已登录为 {session.user.name}。</div>;
  }

  if (providers.length === 0) {
    return <div>未配置社交登录方法。</div>;
  }

  return (
    <div>
      <h3>使用社交媒体登录</h3>
      {providers.map((p) => (
        <button key={p.provider} onClick={() => handleLogin(p)} disabled={loading}>
          {loading ? '登录中...' : `使用 ${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 并将其绑定到当前用户的会话。</x-field-desc>
  </x-field>
  <x-field data-name="disconnectPasskey" data-type="function" data-required="true">
    <x-field-desc markdown>成功验证后，从当前用户的会话中解绑 Passkey。</x-field-desc>
  </x-field>
  <x-field data-name="switchPassport" data-type="function" data-required="true">
    <x-field-desc markdown>启动一个流程，用于在不同的已连接帐户（通行证）之间切换。</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 自动更新。
    } catch (err) {
      setError(err.message);
      console.error('Passkey login failed:', err);
    }
  };

  return (
    <div>
      <button onClick={handleLogin} disabled={passkeyState.loading}>
        {passkeyState.loading ? '验证中...' : '使用 Passkey 登录'}
      </button>
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  );
}
```

这些 hook 提供了将 DID Connect 强大的身份验证功能以完全自定义的 UI 集成到应用程序任何部分的灵活性。要了解如何以编程方式控制预构建的 `DidConnect` 模态框，请继续阅读 [useConnect hook 文档](./hooks-use-connect.md)。