On this page
4 min read

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_TOKEN for register-api; Graph rejected the credentials.
  • Evidence: GET /health returned graph_auth_ok: false; POST /api/register responded 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.

Operational secret

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, writes GRAPH_SERVICE_APP_TOKEN and GRAPH_SERVICE_APP_TOKEN_EXPIRES_AT to register-api/.env.
  • renew-register-api-graph-token.sh: checks health and expiry; renews if graph_auth_ok is 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_USER from register-api/.env. Setup generated the token for the default user (admin) instead of the configured operator. Fix: read GRAPH_SERVICE_USER from .env and pass it with --user to setup.
  • Restart race: verify-register-api.sh ran immediately after docker compose up and failed because register-api had not fully started. Fix: active wait up to 30 s (REGISTER_API_HEALTH_WAIT_SEC) checking graph_auth_ok: true before 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

  1. Health: operators can run ./scripts/verify-register-api.sh in km0-opencloud and confirm graph_auth_ok: true.
  2. Registration: try email/password registration or sign in with Google if you already have an account.
  3. Series: read day 14 (Harari and AI) and day 11 (KM0 Mail).
  4. 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.