-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
When a user upgrades the BitRouter binary from v0.4.x to v0.6.1 in place (without re-running the BYOK wizard), the bitrouter:default auth profile credential stored in openclaw's credential store remains a legacy EdDSA JWT. This token is sent as Authorization: Bearer <token> on every LLM call routed through the bitrouter provider and is rejected by v0.6.1 with 401: invalid JWT signature.
The PR #11 fix to auth.ts handles the plugin-internal token (used for bitrouter_* agent tools) by auto-migrating the keypair on startup. It does not fix the credential stored in openclaw's profile store, because that credential is written once by the BYOK wizard (setup.ts) and only updated by re-running openclaw models auth login --provider bitrouter.
Root cause
setup.ts line ~179:
const { apiToken: jwt } = ensureAuth(homeDir);
// ...
return {
profiles: [{ profileId: "bitrouter:default", credential: { type: "api_key", key: jwt } }],
// ...
};The jwt is written into the openclaw credential store at wizard time. On subsequent gateway restarts the credential is loaded from the store as-is — there is no check whether the stored token's alg header is still compatible with the running binary.
Root cause (plugin side)
No mechanism exists to detect a stale/incompatible token and refresh it without re-running the wizard. The plugin activate path has no access to the stored credential to validate it.
Current workaround
Stop the gateway, manually replace the key field in all ~/.openclaw/agents/*/agent/auth-profiles.json files with a fresh SOL_EDDSA token from ensureAuth, then restart.
Options (needs discussion)
A — Validate and re-mint in index.ts on activation: During activate, read bitrouter:default from the store, decode the JWT header, and if alg !== "SOL_EDDSA" push an updated token via api.updateProviderCredential(...) — if that API exists or can be added to the SDK.
B — Detect and warn: On activation, emit a logger.warn if a legacy token is detected, directing the user to re-run openclaw models auth login --provider bitrouter. Lower complexity but requires manual user action.
C — Store token path, not token value: setup.ts writes only the homeDir path into the profile rather than a minted token; the token is resolved live from the filesystem at request time. Sidesteps staleness entirely but requires a protocol change between the plugin and openclaw's auth layer.
D — Version-keyed re-auth: Track the binary version in the plugin state dir; if it changes, silently re-mint and push an updated credential.
Questions for discussion
- Does the OpenClaw plugin API expose a way for a plugin to update its own credential profile from within
activate? If not, is that worth adding to the SDK? - Is Option C (live token resolution) feasible given how openclaw passes auth credentials to provider requests?
- What's the preferred UX — silent auto-migration (A/D) or explicit user prompt (B)?