Skip to content

Commit 7da13f2

Browse files
committed
Fix uriHandler for OAuth flow
1 parent c78d826 commit 7da13f2

File tree

4 files changed

+68
-4
lines changed

4 files changed

+68
-4
lines changed

src/oauth/authorizer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export class OAuthAuthorizer implements vscode.Disposable {
155155
application_type: "web",
156156
grant_types: ["authorization_code"],
157157
response_types: ["code"],
158-
client_name: "VS Code Coder Extension",
158+
client_name: `Coder for ${vscode.env.appName}`,
159159
token_endpoint_auth_method: "client_secret_post",
160160
};
161161

src/uri/uriHandler.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { errToStr } from "../api/api-helper";
44
import { type Commands } from "../commands";
55
import { type ServiceContainer } from "../core/container";
66
import { type DeploymentManager } from "../deployment/deploymentManager";
7+
import { CALLBACK_PATH } from "../oauth/utils";
78
import { maybeAskUrl } from "../promptUtils";
89
import { toSafeHost } from "../util";
910

@@ -16,10 +17,10 @@ interface UriRouteContext {
1617

1718
type UriRouteHandler = (ctx: UriRouteContext) => Promise<void>;
1819

19-
const routes: Record<string, UriRouteHandler> = {
20+
const routes: Readonly<Record<string, UriRouteHandler>> = {
2021
"/open": handleOpen,
2122
"/openDevContainer": handleOpenDevContainer,
22-
CALLBACK_PATH: handleOAuthCallback,
23+
[CALLBACK_PATH]: handleOAuthCallback,
2324
};
2425

2526
/**

test/unit/oauth/testUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export function createBaseTestContext() {
9191
vi.mocked(getHeaders).mockResolvedValue({});
9292

9393
// Constructor sets up vscode.workspace mock
94-
new MockConfigurationProvider();
94+
const _configurationProvider = new MockConfigurationProvider();
9595

9696
const secretStorage = new InMemorySecretStorage();
9797
const memento = new InMemoryMemento();

test/unit/uri/uriHandler.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as vscode from "vscode";
33

44
import { MementoManager } from "@/core/mementoManager";
55
import { SecretsManager } from "@/core/secretsManager";
6+
import { CALLBACK_PATH } from "@/oauth/utils";
67
import { maybeAskUrl } from "@/promptUtils";
78
import { registerUriHandler } from "@/uri/uriHandler";
89

@@ -318,4 +319,66 @@ describe("uriHandler", () => {
318319
);
319320
});
320321
});
322+
323+
describe(CALLBACK_PATH, () => {
324+
type CallbackData = {
325+
state: string;
326+
code: string | null;
327+
error: string | null;
328+
};
329+
330+
it("stores OAuth callback with code and state", async () => {
331+
const { handleUri, secretsManager } = createTestContext();
332+
333+
const callbackPromise = new Promise<CallbackData>((resolve) => {
334+
secretsManager.onDidChangeOAuthCallback(resolve);
335+
});
336+
337+
await handleUri(
338+
createMockUri(CALLBACK_PATH, "code=auth-code&state=test-state"),
339+
);
340+
341+
const callbackData = await callbackPromise;
342+
expect(callbackData).toEqual({
343+
state: "test-state",
344+
code: "auth-code",
345+
error: null,
346+
});
347+
});
348+
349+
it("stores OAuth callback with error", async () => {
350+
const { handleUri, secretsManager } = createTestContext();
351+
352+
const callbackPromise = new Promise<CallbackData>((resolve) => {
353+
secretsManager.onDidChangeOAuthCallback(resolve);
354+
});
355+
356+
await handleUri(
357+
createMockUri(CALLBACK_PATH, "state=test-state&error=access_denied"),
358+
);
359+
360+
const callbackData = await callbackPromise;
361+
expect(callbackData).toEqual({
362+
state: "test-state",
363+
code: null,
364+
error: "access_denied",
365+
});
366+
});
367+
368+
it("does not store callback when state is missing", async () => {
369+
const { handleUri, secretsManager } = createTestContext();
370+
371+
let callbackReceived = false;
372+
secretsManager.onDidChangeOAuthCallback(() => {
373+
callbackReceived = true;
374+
});
375+
376+
await handleUri(createMockUri(CALLBACK_PATH, "code=auth-code"));
377+
378+
// Flush microtask queue to ensure any async callback would have fired
379+
await Promise.resolve();
380+
381+
expect(callbackReceived).toBe(false);
382+
});
383+
});
321384
});

0 commit comments

Comments
 (0)