| Crates.io | openkit403 |
| lib.rs | openkit403 |
| version | 0.1.0 |
| created_at | 2025-12-01 12:53:42.895449+00 |
| updated_at | 2025-12-01 12:53:42.895449+00 |
| description | HTTP-native wallet authentication for Solana |
| homepage | |
| repository | https://github.com/openkitx403/openkit403-rust |
| max_upload_size | |
| id | 1959746 |
| size | 98,508 |
HTTP-native wallet authentication for Solana in Rust.
Add to your Cargo.toml:
[dependencies]
openkit403 = "0.1.0"
# For Axum
openkit403 = { version = "0.1.0", features = ["axum"] }
# For Actix-Web
openkit403 = { version = "0.1.0", features = ["actix"] }
Or use cargo:
cargo add openkit403
cargo add openkit403 --features axum
cargo add openkit403 --features actix
use axum::{
body::Body,
extract::Request,
middleware,
response::Json,
routing::get,
Router,
};
use openkit403::{
axum_middleware::{extract_user, openkit403_middleware},
Config, InMemoryReplayStore,
};
use std::sync::Arc;
#[tokio::main]
async fn main() {
let mut config = Config::new(
"https://api.example.com".to_string(),
"my-server".to_string(),
);
config.replay_store = Some(Box::new(InMemoryReplayStore::new()));
let config = Arc::new(config);
let app = Router::new()
.route("/protected", get(protected_handler))
.route_layer(middleware::from_fn_with_state(
config.clone(),
openkit403_middleware,
));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn protected_handler(request: Request<Body>) -> Json<serde_json::Value> {
let user = extract_user(&request).expect("User authenticated");
Json(serde_json::json!({
"wallet": user.address
}))
}
use actix_web::{get, web, App, HttpRequest, HttpResponse, HttpServer};
use openkit403::{actix_middleware::OpenKit403User, Config, InMemoryReplayStore};
use std::sync::Arc;
#[get("/protected")]
async fn protected_handler(req: HttpRequest) -> HttpResponse {
let user = req.extensions().get::<OpenKit403User>().unwrap();
HttpResponse::Ok().json(serde_json::json!({
"wallet": user.address
}))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let mut config = Config::new(
"https://api.example.com".to_string(),
"my-server".to_string(),
);
config.replay_store = Some(Box::new(InMemoryReplayStore::new()));
let config = Arc::new(config);
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(config.clone()))
.service(protected_handler)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
use openkit403::{Config, InMemoryReplayStore};
let mut config = Config::new(
"https://api.example.com".to_string(),
"my-server".to_string(),
);
config.ttl_seconds = 60;
config.clock_skew_seconds = 120;
config.bind_method_path = false;
config.origin_binding = false;
config.ua_binding = false;
config.replay_store = Some(Box::new(InMemoryReplayStore::new()));
use openkit403::TokenGate;
struct MyTokenGate;
impl TokenGate for MyTokenGate {
fn check(&self, address: &str) -> Result<bool, Box<dyn std::error::Error>> {
// Check if wallet holds required token
Ok(check_token_balance(address) > 0)
}
}
config.token_gate = Some(Box::new(MyTokenGate));
use openkit403::{verify_authorization, Config};
use std::collections::HashMap;
let result = verify_authorization(
&auth_header,
"GET",
"/api/resource",
&config,
Some(&headers),
).await;
if result.ok {
println!("Authenticated: {}", result.address.unwrap());
}
Ensure your Cargo.toml has correct metadata:
[package]
name = "openkit403"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "HTTP-native wallet authentication for Solana"
repository = "https://github.com/openkitx403/openkit403-rust"
cargo build --all-features
cargo test --all-features
cargo doc --no-deps
# Login to crates.io (first time only)
cargo login
# Publish
cargo publish --dry-run
cargo publish
# Update version in Cargo.toml, then:
git commit -am "Release v0.2.0"
git tag v0.2.0
git push origin main --tags
cargo publish
# Axum
cargo run --example axum-server --features axum
# Actix-Web
cargo run --example actix-server --features actix
cargo test
cargo test --all-features
MIT