-
Pick a strong shared secret and export it before starting the server:
export SHORTENER_SECRET="replace-with-a-random-string" php -S 0.0.0.0:8080 -t webroot
-
Create a short link with an authenticated API call:
SECRET="$SHORTENER_SECRET" TIMESTAMP=$(date -u +%s) BODY='{"url":"https://example.org"}' CANONICAL=$(printf "%s\n%s\n%s\n%s" "$TIMESTAMP" "POST" "/api/shorten" "$BODY") SIGNATURE=$(printf "%s" "$CANONICAL" | openssl dgst -sha256 -mac HMAC -macopt "key:$SECRET" -binary | base64) curl -X POST http://127.0.0.1:8080/api/shorten \ -H "Content-Type: application/json" \ -H "X-Timestamp: $TIMESTAMP" \ -H "X-Signature: $SIGNATURE" \ -d "$BODY"
The signature is calculated as
base64(hmac_sha256(timestamp + "\n" + METHOD + "\n" + PATH + "\n" + body, secret))and requests are only accepted when the timestamp is within five minutes of the server time. -
Resolve a short link (no authentication required):
curl -i http://127.0.0.1:8080/abc
Import-Module "$PSScriptRoot/powershell/ShortenerClient.psm1"
$env:SHORTENER_SECRET = "replace-with-a-random-string"
New-ShortLink -Url "https://example.org" -ApiBaseUrl "http://127.0.0.1:8080"
Get-ShortLink -Code "abc" -ApiBaseUrl "http://127.0.0.1:8080"Run the API with Docker Compose:
export SHORTENER_SECRET="replace-with-a-random-string"
docker compose up --buildThe service listens on http://localhost:8080 and stores its SQLite database in ./data/shortener.sqlite on the host.
POST /api/shorten(authenticated) accepts{"url": "https://target"}and returns thecode,short_url,target_url, andcreated_atfields.GET /api/links/{code}(authenticated) returns metadata about an existing short link.GET /{code}(public) issues an HTTP redirect to the stored target URL.
Links are stored in data/shortener.sqlite using SQLite. The database and schema are created automatically on first run.