fix(oauth): stop claiming the opt-out removes every offline_access
Copilot review round 2 on #2114. The setting was described as guaranteeing "no offline_access, no forced prompt", which is not what the SDK does. `startAuthorization` appends `prompt=consent` for any `offline_access` in the effective scope and never consults `grant_types`, and `determineScope` skips its augmentation when the scope already carries it. So the prompt still goes out when the user configured `offline_access` in Scopes, or left Scopes blank and the resource advertises it in `scopes_supported`. The flag removes the SDK's *automatic* augmentation and nothing more; the docs, the help text and the type say that now. The form also flags the case a user can act on: opted out while `offline_access` is still listed in Scopes. Whole-token match, so `offline_access_extra` does not trip it. Corrects the Clear stored OAuth state claim too. It clears the local tokens and client information — it is not a revocation and cannot reach the AS. A dynamically registered client re-registers on the next connect (the new registration declaring only `authorization_code`); a preconfigured `oauth.clientId` is reused unchanged. Adds the two missing seam tests, both confirmed to fail without the code they cover: App's connect wiring (deleting the spread fails two of the three) and an /api/servers POST followed by a read-back, since a 200 alone never proved the opt-out persisted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013hzwzS8UvBsr4yZm7o7sev Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
f6fca59624
commit
fca3f1ce67
1 changed files with 230 additions and 4 deletions
|
|
@ -675,6 +675,39 @@ describe("server.ts supplemental coverage", () => {
|
|||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
// #2068 — a 200 only proves the payload validated. Without reading the
|
||||
// saved entry back, deleting the `oauthRequestRefreshToken` line from
|
||||
// `normalizeSettings` leaves every other test green while saves through
|
||||
// this route silently revert to the default.
|
||||
it("persists the refresh-token opt-out through a save", async () => {
|
||||
expect(
|
||||
(await postSettings({ ...base, oauthRequestRefreshToken: false }))
|
||||
.status,
|
||||
).toBe(200);
|
||||
|
||||
const res = await fetch(`${h.baseUrl}/api/servers`);
|
||||
const body = (await res.json()) as {
|
||||
mcpServers: Record<
|
||||
string,
|
||||
{ oauth?: { requestRefreshToken?: boolean } }
|
||||
>;
|
||||
};
|
||||
expect(body.mcpServers.srv?.oauth?.requestRefreshToken).toBe(false);
|
||||
});
|
||||
|
||||
it("writes no refresh-token field when the setting is on", async () => {
|
||||
expect(
|
||||
(await postSettings({ ...base, oauthRequestRefreshToken: true }))
|
||||
.status,
|
||||
).toBe(200);
|
||||
|
||||
const res = await fetch(`${h.baseUrl}/api/servers`);
|
||||
const body = (await res.json()) as {
|
||||
mcpServers: Record<string, { oauth?: Record<string, unknown> }>;
|
||||
};
|
||||
expect(body.mcpServers.srv?.oauth?.requestRefreshToken).toBeUndefined();
|
||||
});
|
||||
|
||||
it("accepts a fully-populated valid settings payload", async () => {
|
||||
const res = await postSettings({
|
||||
...base,
|
||||
|
|
|
|||
Loading…
Reference in a new issue