# Hessra API
HTTP client for Hessra authentication and authorization services.
This crate provides a client for making HTTP requests to the Hessra services. It supports both HTTP/1.1 and HTTP/3 (as an optional feature) and implements the OpenAPI specification for the Hessra service.
## Features
- HTTP/1.1 client for Hessra services
- Optional HTTP/3 support via the `http3` feature flag
- Dual authentication support: mTLS and identity tokens
- Identity token endpoints for authentication without certificates
- Authorization token endpoints with optional identity token authentication
- Multi-party token signing via the `/sign_token` endpoint
- Mutual TLS (mTLS) for secure client authentication (optional for most endpoints)
- Bearer token authentication using identity tokens
- Proper error handling with custom error types
- Comprehensive test coverage
## Usage
### Creating a Client
```rust
use hessra_api::HessraClient;
use hessra_config::HessraConfig;
// Load configuration from environment variables
let config = HessraConfig::from_env("HESSRA")?;
// Create a client using the configuration
let client = HessraClient::builder()
.from_config(&config)
.build()?;
// Or create a client manually
let client = HessraClient::builder()
.base_url("test.hessra.net")
.port(443)
.protocol(Protocol::Http1)
.mtls_cert(include_str!("../certs/client.crt"))
.mtls_key(include_str!("../certs/client.key"))
.server_ca(include_str!("../certs/ca.crt"))
.public_key("optional-public-key")
.personal_keypair("optional-keypair")
.build()?;
```
### Identity Tokens
```rust
// Request a new identity token (requires mTLS)
let identity_response = client.request_identity_token(Some("urn:hessra:alice")).await?;
let identity_token = identity_response.token;
// Refresh an identity token (can use existing token for auth)
let refreshed = client.refresh_identity_token(
identity_token.clone(),
Some("urn:hessra:alice")
).await?;
```
### Requesting Authorization Tokens
```rust
// Request a token using mTLS authentication
let resource = "example-resource".to_string();
let operation = "read".to_string();
let token = client.request_token(resource, operation).await?;
// Request a token using identity token authentication (no mTLS required)
let token = client.request_token_with_identity(
"example-resource",
"read",
identity_token
).await?;
```
### Verifying a Token
```rust
// Verify the token
let subject = "example-user".to_string();
let resource = "example-resource".to_string();
let operation = "read".to_string();
let result = client.verify_token(token, subject, resource, operation).await?;
```
### Getting the Public Key
The public_key endpoint is available for both authenticated and unauthenticated requests. If requesting the public_key with an authenticated request and authentication fails, the request will fail.
```rust
// Retrieve the server's public key
let public_key = client.get_public_key().await?;
// Or fetch the public key without creating a client
let public_key = HessraClient::fetch_public_key(
"test.hessra.net",
Some(443),
include_str!("../certs/ca.crt"),
).await?;
```
### Verifying a Service Chain Token
```rust
// Verify a service chain token
let result = client.verify_service_chain_token(
token,
subject,
resource,
operation,
Some("component-name".to_string()), // or None to verify the token against the full service chain
).await?;
```
### Multi-Party Token Signing
Sign a token that requires multi-party authorization:
```rust
// Sign a token using the /sign_token endpoint
let signed_response = client.sign_token(
"token_to_sign",
"resource_name",
"operation"
).await?;
if let Some(signed_token) = signed_response.token {
println!("Token signed successfully: {}", signed_token);
} else if let Some(pending_signoffs) = signed_response.pending_signoffs {
println!("Token still requires {} more signoffs", pending_signoffs.len());
}
```
## HTTP/3 Support
To use HTTP/3, enable the `http3` feature in your Cargo.toml:
```toml
[dependencies]
hessra-api = { version = "0.5.1", features = ["http3"] }
```
Then create a client with the HTTP/3 protocol:
```rust
let client = HessraClient::builder()
.protocol(Protocol::Http3)
// ... other configuration
.build()?;
```
## Error Handling
The API client provides a custom error type `ApiError` that includes detailed information about any errors that occur. Errors are categorized into specific types such as HTTP client errors, SSL configuration errors, token request errors, etc.
```rust
match client.request_token(resource).await {
Ok(token) => {
// Use the token
},
Err(e) => {
match e {
ApiError::HttpClient(e) => {
// Handle HTTP client error
},
ApiError::SslConfig(e) => {
// Handle SSL configuration error
},
// Handle other error types
_ => {
// Generic error handling
}
}
}
}
```
## Examples
See the `examples` directory for complete usage examples:
- `client_example.rs`: Basic usage of the HTTP/1.1 client
- `http3_example.rs`: Using the HTTP/3 client (requires the `http3` feature)
## Integration with hessra-config
This crate is designed to work seamlessly with the `hessra-config` crate, which provides configuration management for Hessra services. You can create a client directly from a `HessraConfig` instance, which makes it easy to share configuration between multiple components.