Authentication that follows you like a shadow.
shadowauth turns your phone into a tiny, encrypted secrets vault that exposes a small REST API over your local network. Machines near you β laptops, servers, a Raspberry Pi on the same Wi-Fi β can pull credentials on demand instead of storing them on disk. When you (and your phone) leave the network, the secrets leave with you.
Carrying API keys, tokens and SSH keys between machines is annoying and risky. shadowauth lets you keep them in one place, encrypted with your own GPG key, and fetch them over the LAN exactly when a script needs them β so nothing sensitive is left lying around on other computers.
gpg.X-API-Key header (or ?api_key= query
parameter) guards every data route.curl, Python, Node, etc.Every route under /api/secrets requires your API key, supplied either as:
X-API-Key: <your-key>, or?api_key=<your-key> (handy for QR codes and browsers).Requests with a missing or incorrect key receive 401 Unauthorized. If no API
key has been configured in the app yet, all data requests are rejected.
http://<phone-ip>:1613application/jsonGET /api/healthLiveness probe. Open β requires no API key. Returns a small JSON object so a script can confirm the server is reachable before doing real work.
Use case: Your deploy script pings
/api/healthfirst; if the phone isnβt on the network it skips the credential-dependent steps gracefully instead of failing halfway through.
Inputs: none.
Errors: none under normal operation (if you canβt reach it, the server isnβt running or youβre not on the network).
Example
curl http://192.168.1.42:1613/api/health
Response β 200 OK
{ "status": "ok", "app": "shadowauth" }
GET /api/secretsList the names (and timestamps) of all stored secrets. Values are never
included in the listing. Supports an optional q filter that matches anywhere
in the name (case-insensitive).
Use case: A setup wizard on your laptop lists everything in your vault so you can pick which credentials to wire into a new project.
Inputs
q (query, optional) β substring to filter names by.api_key (query) or X-API-Key (header) β required.Errors
401 Unauthorized β missing/invalid API key.Example β list everything
curl -H "X-API-Key: YOUR_KEY" http://192.168.1.42:1613/api/secrets
Example β search
curl -H "X-API-Key: YOUR_KEY" "http://192.168.1.42:1613/api/secrets?q=aws"
Response β 200 OK
[
{ "name": "AWS_SECRET", "createdAt": 1782396606590, "updatedAt": 1782396606590 }
]
GET /api/secrets/{name}Retrieve a single secret and return its decrypted plaintext value. Decryption happens on the device using your private key + stored passphrase.
Use case: A build script runs
export OPENAI_API_KEY=$(curl ...)so the key lives only in that shell session and is never written to a file on the build machine.
Inputs
name (path) β the exact key name.api_key (query) or X-API-Key (header) β required.Errors
401 Unauthorized β missing/invalid API key.404 Not Found β no secret with that name.500 Internal Server Error β no private key/passphrase configured, or
decryption failed.Example
curl -H "X-API-Key: YOUR_KEY" http://192.168.1.42:1613/api/secrets/OPENAI_API_KEY
Response β 200 OK
{ "name": "OPENAI_API_KEY", "value": "sk-live-...." }
POST /api/secretsCreate a new secret (or overwrite an existing one with the same name). The value is encrypted to your GPG public key before it touches storage.
Use case: You rotate a token in your cloud console and push the new value to your phone from your laptop with one
curlcommand, so every machine instantly gets the fresh token next time it asks.
Inputs β JSON body:
name (string, required) β the key name.value (string, required) β the secret value to encrypt.Errors
400 Bad Request β missing name or value.401 Unauthorized β missing/invalid API key.500 Internal Server Error β no public key configured.Example
curl -X POST -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
-d '{"name":"OPENAI_API_KEY","value":"sk-live-...."}' \
http://192.168.1.42:1613/api/secrets
Response β 201 Created
{ "message": "stored" }
PUT /api/secrets/{name}Update the value of an existing secret (re-encrypts the new value). Behaves like
POST but takes the name from the path.
Use case: A cron job on your server regenerates a short-lived database password every night and writes it back to the vault with
PUT.
Inputs
name (path) β the key name.value (string, required).Errors
400 Bad Request β missing value.401 Unauthorized β missing/invalid API key.500 Internal Server Error β no public key configured.Example
curl -X PUT -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
-d '{"value":"new-secret-value"}' \
http://192.168.1.42:1613/api/secrets/OPENAI_API_KEY
Response β 200 OK
{ "message": "updated" }
DELETE /api/secrets/{name}Permanently remove a secret from the vault.
Use case: You decommission a service and delete its now-useless API key from the vault so it never gets handed out again.
Inputs
name (path) β the key name.Errors
401 Unauthorized β missing/invalid API key.404 Not Found β no secret with that name.Example
curl -X DELETE -H "X-API-Key: YOUR_KEY" \
http://192.168.1.42:1613/api/secrets/OPENAI_API_KEY
Response β 200 OK
{ "message": "deleted" }
shadowauth Β· Peaky Meadows Private Limited Β· runs on app.pky.ad conventions.