(feat): migrate to rust

This commit is contained in:
Alois 2026-07-02 22:39:45 +02:00
commit 20b12f3c60
28 changed files with 3365 additions and 2775 deletions

244
README.md
View file

@ -1,74 +1,190 @@
# TypeScript TAuth SDK
# TAuth SDK
TypeScript SDK for TAuth-based login and explicit transport session management.
Rust library for integrating applications with TAuth and MTP.
This SDK starts a local HTTP callback server, verifies a challenge, and gives you explicit control over TTP connections per `userId:sessionId`.
The SDK handles app key material, TAuth login URLs, callback parsing, Omikron lookup, authenticated MTP connections, and loading/saving user-specific app data.
## Requirements
- A modern version of Bun
- A domain with TXT record support
- App x448 key pair (`privateKey`, `publicKey`) (can be generated)
- Rust 1.95+
- A TAuth app identifier, usually your app domain
- An MTP key pair generated by this library
- A public callback URL in your application
## Install
```toml
[dependencies]
tauth-sdk = { git = "https://git.methanium.net/tensamin/tauth-sdk.git" }
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```
## Generate App Keys
Run this once, store the private key securely, and publish the public key where TAuth expects app verification data.
```rust
use tauth_sdk::generate_key_pair;
fn main() {
let keys = generate_key_pair();
println!("private: {}", keys.private);
println!("public: {}", keys.public);
}
```
Keys are base64-encoded MTP key material. Do not expose the private key.
## Create A Client
```rust
use tauth_sdk::{TAuthClient, TAuthConfig};
let client = TAuthClient::from_config(
TAuthConfig::new(
"my.cool.app",
"https://my.cool.app/tauth/callback",
std::env::var("TAUTH_PRIVATE_KEY")?,
)
.frontend_url("https://tauth.tensamin.net/login"),
)?;
```
For the default TAuth frontend, this shorter form is equivalent:
```rust
let client = TAuthClient::new(
"my.cool.app",
"https://my.cool.app/tauth/callback",
std::env::var("TAUTH_PRIVATE_KEY")?,
)?;
```
## Start Login
Redirect the user to `client.auth_url(None)` from your web handler.
```rust
let login_url = client.auth_url(None);
```
The URL includes:
- `identifier`: your app identifier
- `redirect`: your callback URL
- `public_key`: your app MTP public key bundle
- `challenge`: optional caller-supplied challenge
## Handle Callback
In your callback route, parse the full callback URL and persist the returned `user_id` and `session_id` for your user.
```rust
let callback = client.parse_callback(full_callback_url)?;
save_session(callback.user_id, callback.session_id).await?;
```
`AuthCallback` contains:
```rust
pub struct AuthCallback {
pub user_id: u64,
pub session_id: u64,
pub challenge: Option<String>,
pub original_challenge: Option<String>,
pub host_public_key: Option<String>,
}
```
## Connect To TAuth Data Over MTP
If the callback or your application already has the Omikron host public key, pass it explicitly:
```rust
let session = client
.connect_session(callback.user_id, callback.session_id, host_public_key)
.await?;
```
If the Omikron API returns a `public_key`, the SDK can look it up automatically:
```rust
let session = client.session_from_callback(&callback).await?;
```
The connection uses MTP authenticated login with your app keyring and the Omikron host public key.
## Load And Save App Data
Use serde types for application data:
```rust
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct AppData {
name: String,
value: String,
}
let data: AppData = session.load().await?;
session
.save(&AppData {
name: "example".into(),
value: "updated".into(),
})
.await?;
```
Raw JSON is also supported:
```rust
let data = session.load_json().await?;
session.save_json(&data).await?;
```
## Other Helpers
Fetch a TAuth user profile:
```rust
let user = client.user(callback.user_id).await?;
```
Connect directly to a known Omikron URL:
```rust
let connection = client
.connect_to_omikron(user_id, session_id, "https://omikron.example:4433", host_public_key)
.await?;
```
Use lower-level MTP connection helpers when needed:
```rust
let value = tauth_sdk::load_json(&connection).await?;
tauth_sdk::save_json(&connection, &value).await?;
```
## MTP Type Map
This crate compiles an MTP type map for TAuth app data messages:
- `LoadAppData`
- `LoadAppDataResponse`
- `SaveAppData`
- `SaveAppDataResponse`
- `AppData`
The map lives in `type-maps.yaml` and is wired through `.cargo/config.toml` using `MTP_TYPE_MAPS`.
## Development
```bash
bun add https://git.methanium.net/tensamin/tauth-sdk/archive/0.0.3.tar.gz
cargo test
cargo build --release
```
## Generate an app key pair
Use the built-in helper once and store the keys securely:
```ts
import { generateKeyPair } from "@tensamin/tauth-sdk";
const keys = generateKeyPair();
console.log(keys.private);
console.log(keys.public);
```
## Add the TXT record
Add a TXT record at `tauth.your.domain` with your app public key as the value (base64 format). This is used to verify that your app is authorized for your domain.
## Basic usage
```ts
import z from "zod";
import { TAuthClient } from "@tensamin/tauth-sdk";
const client = new TAuthClient({
identifier: "my.cool.app",
privateKey: "<APP_PRIVATE_KEY_BASE64>",
publicKey: "<APP_PUBLIC_KEY_BASE64>",
saveSession: async (userId, sessionId) => {
// You must persist the session id yourself (for example in a database).
// Treat the session id like a password!
console.log("Save session", { userId, sessionId });
},
redirectUrl: "https://my.cool.app/callback", // This should be a public link proxying http://localhost:7878/callback
appData: z.object({
my: z.string(),
cool: z.string(),
data: z.string(),
}),
httpServer: {
hostname: "localhost",
port: 7878,
},
});
```
## Auth endpoints exposed by the SDK
- `GET /auth`: Redirects user to TAuth frontend
- `GET /callback`: Handles challenge flow and invokes your `saveSession(userId, sessionId)` callback
## Connection management
- Use `client.createTTP(userId, sessionId, omikronUrl)` when you want a persistent/manual TTP connection.
- Use `client.loadData(userId, sessionId)` for loading user specific application data.
- Use `client.saveData(userId, sessionId)` for saving user specific application data.
These endpoints need to be exposed behind some kind of http proxy to apply ssl