On this page
Day 15 - OpenCloud registration: expired Graph token and automated renewal
An expired Graph token blocked email registration on KM0 Cloud; we document the cause, safe register-api token rotation, and the defects we found while automating renewal.
Introduction
On day 15 we return to operational infrastructure in the sibling project km0-opencloud. On 4 July 2026 a user tried to register with email and password at KM0 Cloud and saw a generic error. Google OAuth still worked. The cause: the register-api Graph token had expired.
In issue #17 we implemented manual rotation, safe automatic renewal, and fixed two defects the tester found while validating the script. This article explains what happened, why it matters, and what is now automated.
Incident
What the user saw
The form showed the generic message «Could not create the account. Try again later.» without indicating the service was temporarily down. The same user later signed in with Google OAuth without trouble.
- Root cause: expired or invalid
GRAPH_SERVICE_APP_TOKENfor register-api; Graph rejected the credentials. - Evidence:
GET /healthreturnedgraph_auth_ok: false;POST /api/registerresponded HTTP 503. - OAuth intact: Google login uses Dex + OIDC, not register-api; one path worked while the other did not.
- Prior context: issue #16 had already improved form error messages; this day we addressed the operational cause of the 503.
Why
Why register-api needs a token
Email/password registration at KM0 Cloud goes through a sidecar, register-api, that creates users via OpenCloud Graph (POST /graph/v1.0/users). In production Graph does not accept password Basic auth; register-api must authenticate with a dedicated Graph App Token.
That token is a secret with an expiry date. If it expires and nobody renews it, manual registration fails quietly while OAuth keeps working. Treat it as infrastructure credentials, not a «set once and forget» setting.
Implementation
Rotation and auto-renewal (issue #17)
- Policy: token dedicated to register-api only, 3-month lifetime, automatic renewal when fewer than 14 days remain.
setup-register-api-graph-token.sh: creates the token with--expires-in 90d, writesGRAPH_SERVICE_APP_TOKENandGRAPH_SERVICE_APP_TOKEN_EXPIRES_ATtoregister-api/.env.renew-register-api-graph-token.sh: checks health and expiry; renews ifgraph_auth_okis false or margin is low; restarts register-api only; verifies/health.- Cron: weekly template (Monday 03:00 UTC) in
register-api-token-renewal.cron. - Safety: the process never touches users, volumes, Dex/OIDC, databases, or the rest of OpenCloud
.env.
Errors found
What broke when testing automation
The first version of the renewal script passed basic manual tests, but the tester found two defects when running real cron and forced-renewal scenarios.
- Wrong Graph user: the renewal script did not propagate
GRAPH_SERVICE_USERfromregister-api/.env. Setup generated the token for the default user (admin) instead of the configured operator. Fix: readGRAPH_SERVICE_USERfrom.envand pass it with--userto setup. - Restart race:
verify-register-api.shran immediately afterdocker compose upand failed because register-api had not fully started. Fix: active wait up to 30 s (REGISTER_API_HEALTH_WAIT_SEC) checkinggraph_auth_ok: truebefore verify.
After these changes, skip, forced renewal, and 7-day threshold scenarios all exited 0 with graph_auth_ok: true.
Boundaries
What renewal must never do
We documented explicit limits in the km0-opencloud runbook so an automated script cannot damage production.
- Do not run
docker compose down -v,docker volume rm, or OpenCloud user reset commands. - Do not modify Dex, OIDC, storage, databases, or existing groups.
- Only update the register-api token, restart that container, and check health.
- If renewal fails, Google OAuth and existing user data stay intact.
KM0
Why we tell this story on the blog
KM0 promises nearby, operable services: cloud, mail, and web under your control. An expired token is a reminder that operations matter as much as deployment.
- Transparency: if email registration fails, there are now typed messages (issue #16) and documented rotation procedures.
- Safe automation: weekly renewal with minimal scope, not «hero scripts» that restart the whole stack.
- Series: day 14 discussed AI and bureaucracy; here the bureaucracy is a token with an expiry date and a cron job that renews it before users notice.
Verification
Check registration
- Health: operators can run
./scripts/verify-register-api.shin km0-opencloud and confirmgraph_auth_ok: true. - Registration: try email/password registration or sign in with Google if you already have an account.
- Series: read day 14 (Harari and AI) and day 11 (KM0 Mail).
- Ideas: tell us via the ideas form or contact if you want more posts on KM0 Cloud operations.
Series
Previous days
Day 14 summarised Harari's video on AI and civilization; day 13 covered meet 6 on visibility; day 11 documented KM0 Mail. Day 16 announces the Masnou meetup on AI, bureaucracy, and Palantir. Follow the series and try KM0 Cloud whenever you like.