---
title: "@vonvon-kit/tauri"
description: "Tauri v2 桌面 SDK，包含 PKCE S256 流程、deeplink callback 处理器、操作系统 keychain 适配器和 Rust 插件模板。"
locale: "zh-Hans"
---

> Documentation Index
> Fetch the relevant documentation index at: https://vonvon.id/zh-hans/sdks/llms.txt
> Use this file to discover all available pages before exploring further.

# @vonvon-kit/tauri

## 状态

Registry 状态:UNPUBLISHED。此 SDK 只能从仓库源码 checkout 安装；不要使用外部 package registry。

包状态为 **当前包**。JS bridge、PKCE S256 流程、deeplink callback 处理器、操作系统 keychain 适配器和 Rust 插件模板已实现。在真实生产基础设施上的 IdP 往返验证仍待人工核实。

## Tauri 配置

```json
// tauri.conf.json
{
  "bundle": { "identifier": "com.example.myapp" },
  "plugins": {
"deep-link": { "desktop": { "schemes": ["myapp"] } }
  }
}
```

## Rust 插件

将 `templates/vonvon-keychain-plugin.rs` 复制到 `src-tauri/src/vonvon_keychain.rs`，并按照 `templates/tauri-app-setup.rs` 进行注册。将 `keyring = \"2\"`、`tauri-plugin-deep-link = \"2\"` 和 `tauri-plugin-shell = \"2\"` 添加到 `src-tauri/Cargo.toml`。

## JS 集成

```ts
import { createVonvonTauriClient, createTauriKeychainAdapter } from '@vonvon-kit/tauri'
import { invoke } from '@tauri-apps/api/core'
import { open } from '@tauri-apps/plugin-shell'
import { onOpenUrl } from '@tauri-apps/plugin-deep-link'

const client = createVonvonTauriClient({
  issuer: 'https://vonvon.id',
  clientId: 'YOUR_CLIENT_ID',
  redirectUri: 'myapp://auth/callback',
  keychain: createTauriKeychainAdapter({ invoke }),
})

// Register deeplink handler (e.g. on App component mount)
await onOpenUrl(async (urls) => {
  for (const url of urls) await client.handleRedirect(url)
})

// Trigger sign-in: opens system browser
await client.signIn({ openUrl: open })
```

## Token 获取与登出

```ts
// Get the current unexpired access token. Expiry requires a new sign-in.
const token = await client.getAccessToken()

// Get the current unexpired session (userId, organizationId, expiresAt).
const session = await client.getSession()

// Clear local keychain state. No refresh or revoke request is sent.
await client.signOut()

// To request full IdP sign-out, open an explicit OIDC RP-initiated logout URL.
const logoutUrl = client.buildSignOutUrl({ postLogoutRedirectUri: 'myapp://logout' })
await open(logoutUrl.toString())
```

## 不依赖 Tauri 运行时的开发/测试

```ts
import { createVonvonTauriClient, createMemoryKeychainAdapter } from '@vonvon-kit/tauri'

const client = createVonvonTauriClient({
  issuer: 'http://localhost:8788',
  clientId: 'test-client',
  redirectUri: 'http://localhost:1420/callback',
  keychain: createMemoryKeychainAdapter(),
})
```

## createVonvonTauriClient 选项

| 选项 | 类型 | 描述 |
| --- | --- | --- |
| `issuer` | string | Vonvon 签发方 URL |
| `clientId` | string | OAuth 2.0 client\_id |
| `redirectUri` | string | 自定义 URI scheme callback |
| `scopes` | readonly string\[\] | 默认：openid, profile, email |
| `keychain` | VonvonKeychainAdapter | Token 存储适配器；默认为 MemoryKeychainAdapter（生产环境请使用 Tauri 适配器） |

## VonvonTauriClient 方法

| 方式 | 描述 |
| --- | --- |
| `signIn(options?)` | 构建 PKCE 授权 URL；通过 openUrl callback 打开 |
| `handleRedirect(url)` | 解析 deep link，校验 state，交换 code 换取 token |
| `getSession()` | 当前未过期的本地会话返回 TauriSession，否则返回 null；过期状态会被清除 |
| `getAccessToken(options?)` | 当前未过期的 access token 字符串或 null；不会执行 refresh request。在实现 DPoP 之前，SDK 会拒绝 offline\_access。 |
| `signOut()` | 清除本地 keychain 状态，不发送 revoke request |
| `buildSignOutUrl(options?)` | 构建用于 RP 发起登出的 OIDC end\_session URL |
| `setTokenStorage(adapter)` | 在运行时替换 keychain 适配器 |

## PKCE 和 token 存储

- 始终使用 PKCE S256。不生成 plain challenge。
- verifier 熵为 64 字节；challenge 通过 Web Crypto `crypto.subtle.digest('SHA-256', ...)` 派生。
- 所有 key 都位于 `vonvon.*` namespace 下。`vonvon.access_token` 是当前使用的 key。`vonvon.refresh_token` 仅在清理旧数据时删除。`vonvon.session`、`vonvon.pkce_verifier` 和 `vonvon.oauth_state` 保存当前会话和授权状态；不会读取或写入 refresh credential。

Source: https://vonvon.id/zh-hans/sdks/tauri/index.mdx
