- C 20.5%
- JavaScript 20.3%
- Java 15.9%
- PHP 11.3%
- Rust 11.2%
- Other 20.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
SDK-anti-replay tests / rust (push) Successful in 37s
SDK-anti-replay tests / c (push) Successful in 12s
SDK-anti-replay tests / java (push) Successful in 27s
SDK-anti-replay tests / all-sdks-green (push) Successful in 1s
SDK-anti-replay tests / php (push) Successful in 25s
SDK-anti-replay tests / python (push) Successful in 14s
SDK-anti-replay tests / crystal (push) Successful in 26s
SDK-anti-replay tests / javascript (push) Successful in 5s
|
||
| .github/workflows | ||
| C | ||
| Crystal | ||
| Java | ||
| JavaScript | ||
| PHP | ||
| Python | ||
| Rust | ||
| LICENSE | ||
| README.md | ||
SDK-anti-replay
Request-signing SDKs for ProxyAuth's plugin_anti_replay — one implementation per language, each built on that language's most widely used HTTP client:
| Directory | Language | HTTP client used in examples |
|---|---|---|
Python/ |
Python | requests |
PHP/ |
PHP | Guzzle |
Rust/ |
Rust | reqwest |
Crystal/ |
Crystal | HTTP::Client (standard library — no shard needed) |
JavaScript/ |
JavaScript (Node.js, server-side) | axios (base package has zero required dependencies — built on native fetch()) |
C/ |
C | libcurl (also used for URL parsing internally) |
Java/ |
Java | java.net.http.HttpClient (JDK built-in since Java 11 — no external dependency) |
All seven compute the exact same four headers, from the exact same canonical string — see Anti-Replay Protection (plugin_anti_replay) on the ProxyAuth wiki for the full server-side contract this implements.
What every SDK does
For a request you're about to send, each SDK computes:
X-User: <ProxyAuth username>
X-Timestamp: <Unix time, milliseconds>
X-Nonce: <16 random bytes, base64>
X-Signature: <HMAC-SHA256, base64>
The signature covers a canonical string built from the request itself:
METHOD|scheme|host|port|path|query|timestamp|nonce|username|bodyHash
queryincludes its leading?when present, or is empty.bodyHashis the base64 SHA-256 of the raw request body, or empty for a bodyless request.
None of these SDKs talk to the network themselves — each one is a small, dependency-light function/class that computes headers. You attach those headers to a request made with whatever HTTP client you're already using; the per-language example just shows the idiomatic way to do that with the most common one.
Getting the secret
The signing secret isn't something you invent — it's generated automatically by ProxyAuth the first time your account is seen with plugin_anti_replay: true, and emailed to you once (never your login password). See Anti-Replay Protection § Where the secret comes from. If you've lost it, ask an administrator to clear it on your account so a new one is generated and re-sent.
Cross-language interoperability
All seven SDKs are tested against the same fixed golden vector — identical username/secret/method/URL/body/timestamp/nonce — and all seven must produce the byte-identical signature:
X-Signature = C+xOacVhSZ3sV2OZeNKR437Cb6Uxa2Nlq8NRuNZtGtI=
See tests//spec/ in each language's directory. This was verified directly while building this SDK — Python, PHP, Rust, Crystal, JavaScript, C, and Java implementations all independently produce this exact signature for the same inputs.
Integration tests against a mock ProxyAuth server
Each SDK also ships an integration test suite that spins up a small local HTTP server replicating ProxyAuth's plugin_anti_replay verification exactly — same canonical string, HMAC check, timestamp window, and nonce-replay tracking, same unknown_signing_client/invalid_signature/timestamp_out_of_window/replayed_request error codes — and drives it with that language's Signer/ProxyAuthSigner over real HTTP on loopback. None of it talks to a real ProxyAuth instance or the network; it's a faithful, self-contained reimplementation of the verification algorithm used purely for testing.
Every suite covers the same scenarios: a valid signed GET, a valid signed POST with a body, a wrong secret, an unknown username, a body tampered with after signing, a replayed request (same nonce sent twice), an expired timestamp, and missing signature headers entirely.
| Directory | Mock server | Client used to drive it |
|---|---|---|
Python/tests/mock_proxyauth.py |
http.server.ThreadingHTTPServer |
requests (via ProxyAuthSigner) |
PHP/tests/mock-server/router.php |
PHP's built-in server (php -S) |
curl — deliberately not Guzzle, so this runs without composer install |
Rust/tests/integration_mock_server.rs |
Raw TcpListener/TcpStream (std only) |
Same, hand-rolled HTTP/1.1 — avoids a toolchain-sensitive mock-HTTP crate |
Crystal/spec/mock_proxyauth.cr |
HTTP::Server (stdlib) |
HTTP::Client (stdlib) |
JavaScript/tests/mock_proxyauth.js |
node:http |
Both native fetch() (via signRequest/signedFetch) and a real axios client with createAntiReplayInterceptor attached |
C/tests/mock_proxyauth.c |
Raw POSIX sockets + pthreads (no HTTP server library) | Real libcurl client |
Java/tests/MockProxyAuth.java |
com.sun.net.httpserver.HttpServer (JDK built-in) |
Real java.net.http.HttpClient |
Per-language docs
- Python/README.md
- PHP/README.md
- Rust/README.md
- Crystal/README.md
- JavaScript/README.md
- C/README.md
- Java/README.md
License
Apache-2.0, matching ProxyAuth itself.
CI
.forgejo/workflows/sdk-tests.yml runs every SDK's full test suite (golden vector + mock-server integration tests) on every push to main and every pull request — one job per language on ubuntu-latest. This instance's outbound network access is restricted (deb.debian.org/data.forgejo.org/packagist.org work, arbitrary third-party install hosts aren't guaranteed to), so each job installs its own runtime via apt-get against the Debian mirror wherever possible — including Crystal, installed straight from Debian's own archive rather than packages.crystal-lang.org's apt repo, which this runner can't resolve. actions/checkout is the only marketplace action used.