A Rust-based authentication server fulfilling https://github.com/holochain/sbd/blob/main/spec-auth.md, and including an human interactive ops console and automation oriented administration api.
This project is built using:
- Axum: A modular and ergonomic web framework for Rust.
- Tokio: An asynchronous runtime for reliable network applications.
- Askama: Type-safe HTML templates.
- Tower Cookies: Cookie management for session handling.
- OAuth2: Basic OAuth2 client implementation for GitHub authentication.
src/main.rs: Application entry point. Sets up logging, loads configuration, defines routes, and starts the server.src/config.rs: Manages application configuration loaded from environment variables.src/routes_client.rs: Handlers for client-facing authentication routes.src/routes_ops.rs: Handlers for web-based administrative operations (OAuth, dashboard).src/routes_api.rs: Handlers for programmatic administrative API access.src/storage.rs: Abstracted storage layer for Redis interaction.src/github.rs: Utilities for interacting with the GitHub API.templates/: HTML templates used by the application.
- Rust (2024 edition)
- A GitHub OAuth Application (setup instructions below)
To run this application, you need to register a new OAuth application on GitHub:
- Go to your GitHub Developer Settings.
- Select OAuth Apps and click New OAuth App.
- Fill in the details:
- Application Name:
Rust OAuth Service(or your preferred name) - Homepage URL:
http://127.0.0.1:3000(for local development) - Authorization callback URL:
http://127.0.0.1:3000/ops/oauth-callback
- Application Name:
- Click Register application.
- On the application page, you will see the Client ID. Copy this value to
GITHUB_CLIENT_IDin your.envfile. - Click Generate a new client secret. Copy this value to
GITHUB_CLIENT_SECRETin your.envfile.
-
Clone the repository.
-
Set up configuration: Copy
env.exampleto.env:cp env.example .env
Populate the
.envfile with your GitHub App credentials and test organization/team details.Also configure the Redis URL from the docker image (leave as is if default was used) and the API tokens that should be allowed for authentication requests.
-
Run a local valkey:
docker run --rm -p6379:6379 --name some-valkey valkey/valkey
-
Run the application:
cargo run
The server typically starts on
http://127.0.0.1:3000. -
Inject a test request:
curl -v -X PUT -H "content-type: application/json" -d '{"ned": "fred"}' "http://127.0.0.1:3000/request-auth/$(dd if=/dev/random bs=32 count=1 | base64 -w0 | tr '+/' '-_' | tr -d '=')"
The service is compiled as a single binary and configured exclusively via environment variables.
To build a release binary:
cargo build --releaseThe binary will be located at target/release/hc-auth-server.
All configuration is handled via environment variables.
| Variable | Description | Default | Required |
|---|---|---|---|
GITHUB_CLIENT_ID |
Client ID from your GitHub OAuth App | - | Yes |
GITHUB_CLIENT_SECRET |
Client Secret from your GitHub OAuth App | - | Yes |
GITHUB_ORG |
GitHub Organization name for access control | - | Yes |
GITHUB_TEAM |
GitHub Team slug within the org | - | Yes |
SESSION_SECRET |
Secret key for signing session cookies (min 64 chars recommended) | - | Yes |
REDIRECT_URI |
OAuth callback URI sent during token exchange | {scheme}://{HOST}:{PORT}/ops/oauth-callback |
No |
HOST |
Interface to bind to | 127.0.0.1 |
No |
PORT |
Port to listen on | 3000 |
No |
PRODUCTION |
Enables HTTPS scheme and secure cookies | false |
No |
REDIS_URL |
Redis connection URL (standalone). If unset, in-memory storage is used | - | No |
MAX_PENDING_REQUESTS |
Maximum number of pending OAuth flows held in storage | 10 |
No |
API_TOKENS |
Comma-separated list of tokens authorized to call protected API endpoints | - | No |
DRIFT_SECS |
Allowed clock skew in seconds for time-based validation | 300 |
No |
RUST_LOG |
Tracing log level filter | hc_auth_server=debug,tower_http=debug |
No |
Helper for generating session secret:
dd if=/dev/random bs=66 count=1 | base64 -w0- Logs: The application outputs structured logs to stdout using
tracing. Log level can be adjusted withRUST_LOG. - Health: Standard HTTP health checks can be performed against the root endpoint
/(returns public home page) or you may want to ensure the process accepts TCP connections. Note that the restricted operations area is now under/ops-auth.
The server provides three sets of routes: Client, Operations (Ops), and Admin (API).
These routes are used by clients wishing to authenticate.
| Route | Method | Description | Path Elements | Query Params | Error Codes |
|---|---|---|---|---|---|
/now |
GET |
Get a challenge payload for signing. | None | None | 500 (Server Error) |
/request-auth/{key} |
PUT |
Request authentication for a public key. | {key}: Base64URL encoded Ed25519 public key. |
None | 401 (Invalid Key), 429 (Too many pending), 500 (Storage Error) |
/authenticate |
PUT |
Finalize authentication with a signed challenge. | None | None | 401 (Unauthorized/Invalid Sig), 500 (Storage Error) |
Notes on /authenticate:
- Requires
Content-Type: application/octet-stream. - Body must be a UTF-8 JSON string containing
pubKey,signature, andpayload(all Base64URL encoded). payloadmust be exactly what was returned by/now.
These routes are used by administrators via the web interface.
| Route | Method | Description | Path Elements | Query Params | Error Codes |
|---|---|---|---|---|---|
/ |
GET |
Home page. | None | error: Optional error message. |
500 (Render Error) |
/ops/auth |
GET |
Management dashboard (requires login). | None | view_key: Optional key to view details. |
302 (Redirect if not logged in) |
/ops/approve |
POST |
Approve a pending request (requires CSRF). | None | None | 302 (Redirect on success/error) |
/ops/block |
POST |
Block a request (requires CSRF). | None | None | 302 (Redirect on success/error) |
/ops/delete |
POST |
Delete a request (requires CSRF). | None | None | 302 (Redirect on success/error) |
/ops/logout |
GET |
Log out from the management session. | None | None | 302 (Redirect to /) |
/ops/oauth-login |
GET |
Initiate GitHub OAuth login. | None | None | 302 (Redirect to GitHub) |
/ops/oauth-callback |
GET |
GitHub OAuth callback handler. | None | code, state |
302 (Redirect to home/error) |
These routes provide programmatic access to management functions. All routes require an Authorization: Bearer <token> header.
| Route | Method | Description | Path Elements | Query Params | Error Codes |
|---|---|---|---|---|---|
/api/list |
GET |
List all requests with states. | None | None | 401 (Unauthorized), 500 (Server Error) |
/api/get/{key} |
GET |
Get details (state, data) for a specific key. | {key}: Base64URL encoded public key. |
None | 401 (Unauthorized), 404 (Not Found) |
/api/transition |
POST |
Move a key between states. | None | None | 400 (Invalid state), 401 (Unauthorized), 500 (Error) |
Notes on API routes:
/api/listreturns[{ "state": "...", "pubKey": "..." }, ...]./api/get/{key}returns{ "state": "...", "pubKey": "...", "data": { ... } }./api/transitionbody:{ "pubKey": "...", "oldState": "...", "newState": "..." }. Valid states:pending,authorized,blocked.
- Ensure the
SESSION_SECRETis kept secure and rotated if compromised. - The service is stateless regarding session data (stored in signed cookies), allowing for horizontal scaling behind a load balancer, provided cookie sticking/affinity is not required by
tower-cookies(it is not, as state is client-side).