---
title: "sdk/linux"
description: "Linux 桌面 Rust SDK，使用 xdg-open 启动浏览器、loopback TCP 处理授权 callback、PKCE S256 和 freedesktop.org Secret Service token 存储。"
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.

# sdk/linux

## 状态

包状态为**已在本地实现并验证**。Rust 单元测试套件已通过。Secret Service D-Bus 存储、xdg-open、完整的 loopback callback 和真实 IdP 往返仍需桌面 Linux 集成环境。本页记录的是已实现行为，不代表已具备生产就绪状态。

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

## 要求

- Rust（stable，2021 版本）
- tokio 异步运行时
- 桌面 Linux 使用 xdg-open（xdg-utils）启动系统浏览器，并需要运行中的 D-Bus 会话及 gnome-keyring 或 kwallet 用于 Secret Service 存储
- 无界面 / CI 环境：使用 in-memory-storage 特性或直接注入 InMemoryStorage

## 安装

将 vonvon-linux 添加到 Cargo.toml：

```toml
[dependencies]
vonvon-linux = { path = "../vonvon/sdk/linux" }
tokio = { version = "1", features = ["full"] }
```

## 快速开始

```rust
use vonvon_linux::{VonvonClient, VonvonConfigBuilder};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 1. Build config. offline_access is rejected until DPoP is implemented.
let config = VonvonConfigBuilder::new()
    .issuer("https://vonvon.id")
    .client_id("your_client_id")
    .redirect_uri("http://127.0.0.1:51234/callback")
    .redirect_port(51234)
    .build()?;

// 2. Create client (default: Secret Service storage)
let client = VonvonClient::configure(config)?;

// 3. Sign in. xdg-open launches the browser and loopback TCP receives the callback.
let session = client.sign_in(None).await?;
println!("user: {}", session.user.sub);

// 4. Get the current unexpired access token. Expiry returns SessionExpired.
let token = client.get_access_token(None).await?;

// 5. Clear local token and guest state. No revoke request is sent.
client.sign_out().await?;
Ok(())
}
```

## 无界面 / CI 用法

当 D-Bus Secret Service 守护进程不可用时，传入 InMemoryStorage 以避免运行时错误：

```rust
use vonvon_linux::{VonvonClient, VonvonConfigBuilder};
use vonvon_linux::storage::InMemoryStorage;
use std::sync::Arc;

let config = VonvonConfigBuilder::new()
.issuer("https://vonvon.id")
.client_id("your_client_id")
.redirect_uri("http://127.0.0.1:51234/callback")
.build()?;

let client = VonvonClient::configure_with_storage(config, Arc::new(InMemoryStorage::new()))?;
```

## 核心 API

| 方式 | 描述 |
| --- | --- |
| `VonvonConfigBuilder::new()` | VonvonConfig 的构建器。必填字段：issuer、client\_id、redirect\_uri。可选：scopes、redirect\_port（默认 51234）、http\_timeout\_secs（默认 30）。 |
| `VonvonClient::configure(config)` | 使用默认 SecretServiceStorage 创建客户端。 |
| `VonvonClient::configure_with_storage(config, adapter)` | 使用自定义 StorageAdapter（例如 InMemoryStorage）创建客户端。 |
| `sign_in(options) async` | 打开 xdg-open 浏览器，在 redirect\_port 启动 loopback TCP 监听器，等待授权码 callback，交换它，存储 token，并返回 Session。 |
| `get_session() async` | 返回当前存储且未过期的会话；到期会清除本地 token state 并返回 SessionExpired。 |
| `get_access_token(options) async` | 返回当前未过期的 access token；到期或 force\_refresh 会清除本地 token state 并返回 SessionExpired。 |
| `sign_out() async` | 清除本地 token 和 guest session storage；不会发送 revoke request。 |
| `set_token_storage(adapter)` | 在构造后替换存储适配器。 |

## 存储适配器

| 适配器 | 描述 |
| --- | --- |
| `SecretServiceStorage` | 默认。通过 D-Bus 将 token 存储在 freedesktop.org Secret Service（gnome-keyring 或 kwallet）中。需要正在运行的桌面会话。 |
| `InMemoryStorage` | 仅限进程内内存。进程退出时 token 丢失。适用于没有 Secret Service 的测试或 CI 环境。 |

## 安全

- 公共客户端——不存储或传输客户端密钥。
- 仅 PKCE S256。服务器拒绝 plain challenge 方式。
- 在 loopback callback 上验证 OAuth state 以防 CSRF（RFC 8252 loopback 重定向）。
- Secret Service 通过桌面 keyring 守护进程对静态 token 进行加密——应用不直接管理加密密钥。
- 在实现 DPoP 之前，SDK 会拒绝 offline\_access；不会持久化意外返回的 refresh\_token response fields。

## 已知限制

- 已实现并在本地测试基于 JWKS 的 ID token 验证、nonce 验证和 JWKS cache renewal。在达到 L4 支持之前，仍需验证桌面 Secret Service 和真实 IdP round-trip。
- 重定向端口固定，必须与在 Vonvon 控制台注册的 redirect\_uri 匹配。动态端口随机化（RFC 8252）需要动态客户端注册支持。
- 系统浏览器重定向和 Secret Service 存储需要桌面环境证据。

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