Skip to content

fix: scope managed OAuth credentials - #399

Merged
7Sageer merged 2 commits into
MoonshotAI:mainfrom
7Sageer:fix/scoped-managed-oauth-login
Jun 4, 2026
Merged

fix: scope managed OAuth credentials#399
7Sageer merged 2 commits into
MoonshotAI:mainfrom
7Sageer:fix/scoped-managed-oauth-login

Conversation

@7Sageer

@7Sageer 7Sageer commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

No linked issue.

Problem

Running Kimi Code login with a non-default OAuth host or API base URL could leave managed Kimi Code config pointing at that environment while OAuth tokens still shared the default credential slot. A later shell could reuse the wrong token and show a misleading API key error when model provisioning returned unauthorized.

What changed

  • Scope managed Kimi Code OAuth credential refs by OAuth host and API base URL, while preserving the legacy production key.
  • Persist non-default OAuth hosts in config and use config OAuth refs for status, login, logout, usage, feedback, telemetry, provider refresh, and runtime token refresh.
  • Treat managed /models 401/403 responses as OAuth unauthorized and retry via force-refresh/device login.
  • Add regression tests for scoped login, refresh, logout, usage/feedback, config round-trip, and manager cache host separation.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 78f5c1a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@moonshot-ai/agent-core Patch
@moonshot-ai/kimi-code-oauth Patch
@moonshot-ai/kimi-code-sdk Patch
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 4, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/MoonshotAI/kimi-code/@moonshot-ai/kimi-code@78f5c1a
npx https://pkg.pr.new/MoonshotAI/kimi-code/@moonshot-ai/kimi-code@78f5c1a

commit: 78f5c1a

@7Sageer
7Sageer force-pushed the fix/scoped-managed-oauth-login branch from 7c8ee72 to 6a5d882 Compare June 4, 2026 03:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7c8ee72530

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/oauth/src/managed-kimi-code.ts Outdated
Comment on lines +158 to +162
const oauthHost = persistedOAuthHost(options.oauthHost);
return {
storage: 'file',
key: options.key,
oauthHost,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Persist the OAuth host for scoped credential refs

When a user logs into a non-default API baseUrl while using the default OAuth host, this omits oauthHost from the persisted ref even though the generated key was hashed with the default host. In a later shell that sets KIMI_CODE_OAUTH_HOST/KIMI_OAUTH_HOST, oauthHostFor() falls back to that env host for the same stored key, so refresh/runtime token lookup uses credentials scoped for one auth server against another auth server. Persist the host for scoped refs, or make explicit refs independent of the current environment.

Useful? React with 👍 / 👎.

Comment thread packages/node-sdk/src/auth.ts Outdated
Comment on lines +81 to +82
baseUrl: options.baseUrl ?? this.configBaseUrlForLogin(auth.baseUrl),
oauthRef: options.oauthRef ?? this.configOAuthRefForLogin(auth.oauthRef, options),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recompute stale legacy OAuth refs on login

For users who already have a pre-fix non-default managed config, base_url can point at a dev/staging API while oauth.key is still the legacy oauth/kimi-code. A plain /login with no env/CLI overrides now passes that stale config ref through here, and the toolkit treats options.oauthRef.key as authoritative instead of deriving the scoped key from the configured baseUrl, so provisioning writes the legacy key back and the prod/dev credential slot remains shared. Detect legacy/mismatched refs and recompute from the configured endpoints during login.

Useful? React with 👍 / 👎.

Comment on lines +114 to +116
return this.toolkit.getManagedUsage(providerName, {
oauthRef: auth.oauthRef,
baseUrl: auth.baseUrl,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor env endpoint overrides for managed usage

When KIMI_CODE_BASE_URL is set to temporarily target another managed environment while the config still contains a persisted base_url, login() deliberately ignores the configured base URL, but usage and feedback now always pass auth.baseUrl from the config. In that environment override scenario these calls still hit the old configured /usages and /feedback endpoints with the wrong scoped token, so they can report the wrong account or fail authorization; apply the same env-precedence rule used for login before passing baseUrl.

Useful? React with 👍 / 👎.

Comment thread apps/kimi-code/src/cli/telemetry.ts Outdated
Comment on lines +43 to +45
(await options.harness.auth.getCachedAccessToken(
KIMI_CODE_PROVIDER_NAME,
options.config.providers[KIMI_CODE_PROVIDER_NAME]?.oauth,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Don't capture a stale OAuth ref for telemetry

This closes over the config object loaded at startup, but /login and /logout can replace the managed provider and its scoped OAuth ref during the same TUI/CLI process. After switching from one managed environment to another, later telemetry flushes still call getCachedAccessToken with the old ref instead of letting the auth facade read the current config, so events can be sent with the previous environment's token or lose auth entirely; resolve the ref lazily rather than capturing options.config here.

Useful? React with 👍 / 👎.

@7Sageer
7Sageer force-pushed the fix/scoped-managed-oauth-login branch from 6a5d882 to 3e25839 Compare June 4, 2026 04:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e25839ce9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/node-sdk/src/auth.ts Outdated

private expectedOAuthRef(oauthRef: OAuthRef | undefined, baseUrl?: string | undefined): OAuthRef {
return resolveKimiCodeOAuthRef({
oauthHost: this.envOAuthHost() ?? oauthRef?.oauthHost,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match login's OAuth host when base URL is overridden

When only KIMI_CODE_BASE_URL is set over a config that already has oauth.oauthHost, runtime auth recomputes the credential ref with the old configured OAuth host here, but login() discards the configured ref on the same env override and derives the slot from the default/env OAuth host. In that scenario /login writes one scoped token, while status/usage/session auth look in a different slot and can still report logged out or fail authorization unless KIMI_CODE_OAUTH_HOST is also set.

Useful? React with 👍 / 👎.

Comment thread packages/node-sdk/src/auth.ts Outdated
Comment on lines +160 to +162
return this.toolkit.tokenProvider(
providerName,
oauthRef ?? this.resolveRuntimeManagedAuth(providerName).oauthRef,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize configured OAuth refs for runtime auth

For an existing pre-scoping config whose base_url is non-default but whose oauth.key is still oauth/kimi-code, ProviderManager passes that explicit ref into this resolver, so the new configOAuthRefForRuntime repair path is skipped. A normal session can therefore call the non-default API with the legacy production token until the user runs /login; normalize explicit managed refs against the configured provider before building the token provider.

Useful? React with 👍 / 👎.

models,
baseUrl: managedProvider.baseUrl,
oauthKey: managedProvider.oauth.key,
oauthHost: managedProvider.oauth.oauthHost,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Persist refreshed service OAuth refs

Passing oauthHost into applyManagedKimiCodeConfig updates the provider and the managed service refs in the local config, but the patch sent to setConfig below still omits services. Because config patches are deep-merged, a refresh that repairs a scoped ref (for example an old custom-base-url config missing oauth_host) persists the provider ref while moonshot_search/moonshot_fetch keep stale OAuth refs and later resolve tokens against the wrong host; include services in this patch too.

Useful? React with 👍 / 👎.

baseUrl: options.baseUrl,
oauthKey,
oauthHost,
preserveDefaultModel: hadToken,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve defaults when migrating legacy login slots

When an existing non-default managed config still points at the legacy oauth/kimi-code slot, the facade now recomputes the scoped slot before login; if that new slot is empty, hadToken is false even though the user already has the old managed config/token. A plain /login migration then provisions with preserveDefaultModel: false and can reset the user's current default model to the first managed model, whereas the legacy-slot login path used to preserve it; base preservation on the existing managed config or stale-token migration case rather than only the new slot.

Useful? React with 👍 / 👎.

@7Sageer
7Sageer force-pushed the fix/scoped-managed-oauth-login branch from 3e25839 to 5433bad Compare June 4, 2026 04:16

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5433badeb6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +105 to +108
const result = await this.toolkit.logout(
providerName,
this.resolveRuntimeManagedAuth(providerName).oauthRef,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve config when logging out an env override

When KIMI_CODE_BASE_URL/KIMI_CODE_OAUTH_HOST are set temporarily over an existing managed config, resolveRuntimeManagedAuth() returns the env-scoped OAuth ref, so this logs out the override token, but KimiOAuthToolkit.logout() still unconditionally runs the config adapter's remove() for managed:kimi-code. A user who only meant to clear the temporary environment credential therefore loses the persisted provider/models for the configured environment while that configured token remains untouched; use the persisted config ref for config removal, or skip config removal when the runtime ref was produced by env overrides.

Useful? React with 👍 / 👎.

Comment on lines +105 to +108
const result = await this.toolkit.logout(
providerName,
this.resolveRuntimeManagedAuth(providerName).oauthRef,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Delete stale legacy tokens during scoped logout

For an existing pre-scoping config whose base_url is non-default but whose persisted oauth.key is still oauth/kimi-code, this call first normalizes the ref to the new scoped slot before logout. In that migration case the actual legacy token file is left behind while the config is removed, so /logout appears to succeed but the old production credential can still be reused later; when repairing a stale ref for logout, also delete the original configured slot or pass it through before removing config.

Useful? React with 👍 / 👎.

Comment thread packages/node-sdk/src/auth.ts Outdated
Comment on lines +234 to +236
const auth = this.resolveManagedAuth(providerName);
const baseUrl = this.configBaseUrlForRuntime(auth.baseUrl);
return this.configOAuthRefForRuntime(oauthRef ?? auth.oauthRef, baseUrl);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep tool service endpoints aligned with env tokens

When KIMI_CODE_BASE_URL is set over a persisted managed config, this path normalizes every managed OAuth ref to the env-scoped token, including the moonshot_search/moonshot_fetch service refs passed from packages/agent-core/src/rpc/core-impl.ts where the service baseUrl still comes directly from config. In that environment-override session the web search/fetch tools therefore call the old configured /search and /fetch endpoints with the env environment's token; either update the service base URLs under the same override or avoid overriding service refs independently of their endpoints.

Useful? React with 👍 / 👎.

@7Sageer
7Sageer force-pushed the fix/scoped-managed-oauth-login branch from 5433bad to 9ce662b Compare June 4, 2026 04:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9ce662b7bb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

applyManagedKimiCodeConfig(asManaged(config), {
models,
baseUrl: managedProvider.baseUrl,
baseUrl,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid persisting temporary env endpoints on refresh

When KIMI_CODE_BASE_URL is set only to run against a temporary managed environment, baseUrl here comes from managedRuntimeBaseUrl() rather than the persisted provider. If the env environment returns a different model list, this path calls applyManagedKimiCodeConfig() and then setConfig(), permanently rewriting the user's provider (and generated service endpoints) to the env URL after the process exits. Use the env URL only for the fetch/token lookup, or avoid writing the managed provider config while an env override is active.

Useful? React with 👍 / 👎.

Comment on lines +143 to +145
const oauthHost = this.oauthHostFor(options.oauthRef, options.oauthHost);
const oauthKey = options.oauthRef?.key ?? this.defaultOAuthKey(options.baseUrl, oauthHost);
const manager = this.managerFor(name, oauthKey, oauthHost);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive toolkit login slots from env base URLs

When a caller uses KimiOAuthToolkit directly with KIMI_CODE_BASE_URL set and no explicit baseUrl, provisioning still fetches models from that env API via fetchManagedKimiCodeModels, but this computes oauthKey with options.baseUrl as undefined, so the token is written to the default production slot while the generated config points at the env base URL. A later runtime derives the scoped key from that persisted baseUrl and cannot find the token; include the env base URL in the default key/ref derivation or require the same resolved base URL to be passed through login.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78f5c1adca

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +270 to +273
const accessToken = await this.ensureFresh(name, {
oauthRef: options.oauthRef ?? this.defaultOAuthRef(options.baseUrl),
});
const result = await fetchManagedUsage(managedUsageUrl(options.baseUrl), accessToken);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive usage tokens from the env base URL

When KIMI_CODE_BASE_URL is set and a direct KimiOAuthToolkit caller omits options.baseUrl, the request URL below still targets the env endpoint via managedUsageUrl(undefined), but this line derives the token ref with defaultOAuthRef(undefined), i.e. the default production credential slot. After this change, a login/provision call that used the env or explicit base URL writes a scoped token, so getManagedUsage() can hit the env /usages endpoint with the wrong cached token or report logged out; resolve the same env base URL before deriving the fallback ref (and apply the same pattern to feedback).

Useful? React with 👍 / 👎.

Comment on lines +197 to +200
return resolveKimiCodeRuntimeAuth({
configuredBaseUrl: auth.baseUrl,
configuredOAuthRef: oauthRef ?? auth.oauthRef,
}).oauthRef;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve explicit service OAuth refs

When a moonshot_search/moonshot_fetch service is explicitly configured with its own scoped oauth ref, core-impl.ts passes that service ref to this resolver, but this normalization recomputes it against the managed model provider's baseUrl rather than the service's endpoint. If the service points at a different managed environment than the model provider, the service ref is discarded and the tool calls that service with the provider's token; leave explicit refs unchanged unless they are the provider ref, or normalize them with the matching service base URL.

Useful? React with 👍 / 👎.

@7Sageer
7Sageer merged commit 232ed87 into MoonshotAI:main Jun 4, 2026
8 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 4, 2026
sunjie21 pushed a commit to sunjie21/kimi-code that referenced this pull request Jun 4, 2026
* fix: scope managed OAuth credentials

* refactor: centralize managed OAuth auth resolution
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.

1 participant