Skip to content

Commit 0b844fb

Browse files
committed
feat: 🙈 AI did AI stuff
1 parent c0956d6 commit 0b844fb

File tree

3 files changed

+98
-141
lines changed

3 files changed

+98
-141
lines changed

README.md

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,41 +21,77 @@ Can be useful to provide an easy and old-school API key authentication mechanism
2121
- **Frontend**: Web UI in TypeScript + React + Vite
2222
- **Storage**: Valkey, a Redis fork, for token storage
2323

24+
## Security
25+
26+
Static API keys are somewhat less secure than JWT or other modern authentication methods. But they are convenient and widely supported by AI tools.
27+
28+
This is about finding the right balance between security and usability.
29+
30+
Tokens are generated with a cryptographically secure random generator, and stored as salted blake3 hashes in Valkey. If Valkey is compromised, stolen hashes cannot be used to authenticate.
31+
32+
Notably, tokens do not expire. There is no rate limiting or brute-force protection implemented in this service. Brute-forcing 256-bit tokens is not feasible, but consider using additional protections higher up in your stack (e.g., Traefik rate limiting, WAF, etc.).
33+
2434
## Quick Start
2535

2636
### Prerequisites
2737

2838
- Rust 1.90+
2939
- Node.js 24+
3040
- Valkey on `localhost:6379`
31-
- An OAuth2/OIDC provider
41+
- An OAuth2/OIDC provider. Tested with Keycloak.
3242

3343
### Configuration
3444

3545
Create `settings.toml` or use environment variables:
3646

3747
```toml
38-
[http]
48+
# HTTP Server Configuration
3949
address = "127.0.0.1"
4050
port = 8080
4151

42-
[valkey]
43-
url = "redis://localhost:6379"
52+
# Valkey Configuration
53+
valkey_url = "redis://localhost:6379"
54+
# valkey_username = "your-username" # Optional
55+
# valkey_password = "your-password" # Optional
56+
57+
# Token hashing salt (32 bytes hex-encoded, 64 characters)
58+
# IMPORTANT: Keep this secret and consistent across deployments
59+
# token_salt = "................................." # 64 hex chars
60+
61+
# Static files directory (optional, defaults to frontend/dist)
62+
# static_dir = "frontend/dist"
63+
64+
# CORS Configuration
65+
[cors]
66+
enabled = false
67+
# allow_origins = ["http://localhost:5173"] # Comma-separated in env: CORS_ALLOW_ORIGINS
4468

69+
# OAuth2/OIDC Configuration
4570
[oauth]
4671
issuer_url = "https://your-oauth-provider"
4772
# OR: jwks_url = "https://your-jwks-endpoint"
73+
# tenant_id = "your-tenant-id" # Optional
74+
# audiences = ["api://your-app"] # Optional
75+
# jwks_refresh_interval_secs = 300 # Default: 300
4876

4977
[oauth.claims]
5078
subject = "sub"
5179
groups = "groups"
5280

5381
[oauth.admin]
5482
group = "admin"
83+
# group_case_sensitive = false
5584

85+
# Frontend Configuration
5686
[frontend]
5787
oidc_authority = "https://your-oauth-provider"
5888
oidc_client_id = "your-client-id"
89+
# oidc_redirect_uri = "http://localhost:8080/callback" # Optional
90+
# api_base_url = "http://localhost:8080" # Optional
91+
# app_name = "Rusty Valkey Forward Auth" # Default shown
92+
# api_docs_path = "/docs" # Default: /docs
93+
# docs_html = "<p>Custom HTML docs</p>" # Optional
94+
# docs_html_file = "/path/to/docs.html" # Optional
5995
```
6096

6197
### Running

src/config.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ use std::fs;
55
use std::net::IpAddr;
66
use std::path::PathBuf;
77

8+
/// Default token salt (echo rusty-valkey-forward-auth | sha256sum).
9+
pub(crate) const DEFAULT_TOKEN_SALT_HEX: &str =
10+
"3794447850d23a5db972dbe556437ec2edfe4294687843d7f0587bd9535beecf";
11+
812
#[derive(Config)]
913
pub(crate) struct RVFAConfig {
1014
/// Port to listen on.
@@ -29,11 +33,7 @@ pub(crate) struct RVFAConfig {
2933

3034
/// Token hashing salt (32 bytes hex-encoded, 64 characters). Used as the keyed blake3 salt.
3135
/// IMPORTANT: Keep this secret and consistent across deployments.
32-
#[config(
33-
env = "TOKEN_SALT",
34-
// echo rusty-valkey-forward-auth | sha256sum
35-
default = "3794447850d23a5db972dbe556437ec2edfe4294687843d7f0587bd9535beecf"
36-
)]
36+
#[config(env = "TOKEN_SALT")]
3737
pub token_salt: String,
3838

3939
#[config(nested)]
@@ -48,6 +48,7 @@ pub(crate) struct RVFAConfig {
4848

4949
#[config(nested)]
5050
pub frontend: FrontendConfig,
51+
5152
}
5253

5354
impl RVFAConfig {
@@ -69,6 +70,19 @@ impl RVFAConfig {
6970

7071
config.frontend.materialize(&config.oauth)?;
7172

73+
if config.token_salt.trim().is_empty() {
74+
config.token_salt = DEFAULT_TOKEN_SALT_HEX.to_string();
75+
}
76+
77+
if config
78+
.token_salt
79+
.eq_ignore_ascii_case(DEFAULT_TOKEN_SALT_HEX)
80+
{
81+
tracing::warn!(
82+
"TOKEN_SALT is using the built-in default; generate a unique salt for production."
83+
);
84+
}
85+
7286
Ok(config)
7387
}
7488

0 commit comments

Comments
 (0)