Skip to content

refactor(auth): unify OAuth credentials into config.json#138

Closed
kapelame wants to merge 19 commits into
mainfrom
refactor/oauth-into-config
Closed

refactor(auth): unify OAuth credentials into config.json#138
kapelame wants to merge 19 commits into
mainfrom
refactor/oauth-into-config

Conversation

@kapelame
Copy link
Copy Markdown
Collaborator

Summary

Builds on #134 and addresses two pieces of feedback from review:

  1. No separate credentials.json file. OAuth tokens now live inside the existing ~/.mmx/config.json under an oauth subobject. Single source of truth for all CLI state, simpler logout, one file to back up / migrate.

  2. Config.oauthApiHost is optional, derived lazily. A new oauthApiHostFor(config) helper falls back to OAUTH_API_HOSTS[config.region] when the field is unset. This removes the cascade of test-fixture churn that adding it as a required field caused — every command-test mock would have needed an oauthApiHost: '...' line just to typecheck.

Also fixes one pre-existing failing test (test/auth/timeout-fix.test.ts) where the mock response shape and URL pattern weren't updated when the OAuth endpoint changed in #134.

Diff

src/auth/credentials.ts         | load/save/clear now read/write the oauth subobject
src/auth/resolver.ts            | use oauthApiHostFor(); source label "config.json"
src/auth/setup.ts               | use oauthApiHostFor()
src/commands/auth/login.ts      | "Credentials saved to ~/.mmx/config.json"
src/commands/auth/logout.ts     | clear oauth from config.json instead of unlinking the file
src/commands/auth/refresh.ts    | use oauthApiHostFor()
src/config/loader.ts            | drop readCredentialResourceUrl shim, use file.oauth?.resource_url
src/config/paths.ts             | drop getCredentialsPath
src/config/schema.ts            | OAuthCredentials type + oauth field + parser + helper
test/auth/timeout-fix.test.ts   | align refresh mock with new response shape

10 files, +88 / -83.

Resulting ~/.mmx/config.json schema

{
  "api_key": "sk-cp-...",          // optional, as before
  "region": "global",
  "oauth": {                       // new — was a separate credentials.json
    "access_token": "...",
    "refresh_token": "...",
    "expires_at": "2026-05-15T12:34:56Z",
    "token_type": "Bearer",
    "resource_url": "https://api.minimax.io"
  },
  "base_url": "...",
  "output": "text"
}

Test plan

  • bun run typecheck clean
  • bun test 212 / 212 pass
  • bun run lint clean
  • bun run build produces dist/mmx.mjs (138 KB)
  • mmx auth login (CN region) — interactive OAuth completes, tokens saved to config.json
  • mmx auth status — reads oauth subobject correctly (Method: oauth, Source: config.json)
  • mmx auth logout — clears oauth from config.json (api_key untouched if present)

jiemu-minimax and others added 19 commits May 12, 2026 10:54
Server returns expired_in as Unix timestamp (ms), matching the old
user_management protocol and OpenClaw client expectations.
The CLI only uses Device Code Flow. Remove dead code: startBrowserFlow,
waitForCallback, PLATFORM_HOSTS, platformHost config, authorizationUrl
and callbackPort from OAuthConfig.
resource_url from OAuth will not include /anthropic suffix.
Move OAuth tokens from a separate ~/.mmx/credentials.json file into an
'oauth' subobject inside the existing ~/.mmx/config.json. Single source
of truth for all CLI state, simpler logout, one file to back up.

Also makes Config.oauthApiHost optional and derives it lazily via a new
oauthApiHostFor(config) helper, removing the cascade of test-fixture
churn that adding it as a required field would have caused.
The 'returns a fresh token when refresh succeeds' test mock and fetch
interceptor predated the OAuth response-shape changes:
- mock body: add status:'success', rename expires_in -> expired_in
- fetch interceptor: match 'oauth2/token' (was 'oauth/token')
@kapelame kapelame closed this May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants