Sandbox ✅
Engage with LifeCare.ID without requesting access. The sandbox is an isolated instance where you self-register an app and mint a synthetic signed-in user in seconds, then run the full sign-in to grant to token to introspect loop. It holds only synthetic, zero-PHI data, and it is separate from production.
- Base URL: your operator's sandbox host (for example
https://sandbox.lifecare.id), or a local instance you run yourself (see Run it locally). - No operator in the loop: registration and test users are self-service here. Production clients stay operator-provisioned for now (see the roadmap).
- One-time access: the hosted sandbox requires a developer access token (enter
your email + accept the terms, click the magic link). Get it at
https://<portal>/devaccess; the verify page shows a token to use as a Bearer for CLI/CI, and sets a cookie for the browser. A sandbox you run locally has no gate. - Two endpoints, both sandbox-only (they return
404on a production instance):POST /v1/sandbox/clientsandPOST /v1/sandbox/test-identity.
1. Register your app (self-service)
On the hosted sandbox, pass your developer access token (from /devaccess) as a Bearer.
(A local sandbox you run yourself needs no token.)
DEVACCESS=… # the token shown on the /devaccess verify page
curl -s -X POST "$SANDBOX/v1/sandbox/clients" \
-H "Authorization: Bearer $DEVACCESS" \
-H "Content-Type: application/json" \
-d '{"name":"My app","redirect_uris":["http://localhost:4000/callback"]}'
{
"client_id": "sbx_Zy47k_NDW4E",
"client_secret": "qDkujP10i72…",
"redirect_uris": ["http://localhost:4000/callback"],
"note": "Sandbox client. Store the secret now - it is not shown again."
}
You now have a client_id and client_secret, the same credentials an operator
would otherwise issue you. redirect_uris is an exact-match allowlist; pass every
callback URL you will use.
2. Mint a test identity (no passkey)
Production sign-in needs a real WebAuthn passkey on a device, which you cannot script. In the sandbox you can mint a synthetic signed-in user instead, so the whole loop runs headlessly (CI, curl, tests):
curl -s -X POST "$SANDBOX/v1/sandbox/test-identity" -H "Content-Type: application/json" -d '{}'
{
"did": "did:web:sandbox.example:u:817612d13f3219b6",
"session_token": "lcs_…",
"expires_at": "2026-06-24T09:00:00+00:00",
"note": "Synthetic sandbox identity (no passkey)."
}
The session_token is a real user/session token. Use it two ways:
- As
Authorization: Bearer lcs_…against the consent panel API. - As the
lc_id_sessioncookie to drive the federation flow (/authorize), exactly as a browser session would.
3. Run the whole loop
With a client and a test identity you can exercise everything:
# (a) act as the signed-in user: set the session cookie, then run /authorize -> /token
# (this is what the app quickstart does for you)
# (b) grant consent for a scope
curl -s -X POST "$SANDBOX/v1/consent/grant" -H "Content-Type: application/json" -d '{
"subject_did":"'"$DID"'","grantee":{"name":"My app","id":"'"$CLIENT_ID"'"},
"scopes":["cgm"],"purpose":{"text":"demo"},"duration_days":1}'
# (c) issue a data-access token, then introspect it
curl -s -X POST "$SANDBOX/v1/token" -H "Content-Type: application/json" -d '{
"subject_did":"'"$DID"'","scope":"cgm","purpose":"demo","requester":"'"$CLIENT_ID"'"}'
curl -s -X POST "$SANDBOX/v1/token/introspect" -H "Content-Type: application/json" -d '{"token":"lc_…"}'
The quickstart repos run this end to end. Point them at your sandbox base URL and the credentials from step 1.
What the sandbox is (and isn't)
- Isolated and synthetic. Separate instance, separate state, zero PHI. Nothing here touches production data or identities.
- Not a passkey bypass for production. The test-identity path exists only on a
sandbox instance; a production instance returns
404for it. Production sign-in is always a real passkey, and an app can never act as a user (see Authorization & tokens). - For building and testing, not for real users or real data. When you are ready for production, you move to operator-provisioned credentials (self-service production registration is on the roadmap).
Run it locally
The sandbox is the same service with one flag. To run your own:
LIFECAREID_SANDBOX=true \
LIFECAREID_STATE_DIR=/tmp/lifecareid-sandbox \
LIFECAREID_DOMAIN=sandbox.local \
uv run uvicorn --factory lifecareid:create_app --port 8821
# → http://localhost:8821 (set SANDBOX=http://localhost:8821 for the curls above)
Operators host a shared sandbox by running this profile as a separate instance with
isolated state; the production instance leaves LIFECAREID_SANDBOX unset, so it never
exposes these routes.