Skip to content

Commit 2ed5eeb

Browse files
test(management): cover telemetry header + mTLS fetch; drop dead export asserts
- token-provider: add TC-2.18/2.19/2.20 covering the previously untested buildTelemetryHeader path — telemetry:false omits the Auth0-Client header, clientInfo override sets custom name/version, and the default header decodes to valid identity JSON. - fetch-option: add a test asserting the supplied mTLS fetch is actually invoked for the api/v2 request (prior mTLS test only checked construction). - export-surface: remove the AuthenticationClient/UserInfoClient absence assertions — both classes are deleted, so the checks were trivially true. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d06dcbc commit 2ed5eeb

3 files changed

Lines changed: 93 additions & 8 deletions

File tree

‎src/management/tests/unit/management-client-fetch-option.test.ts‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,43 @@ describe("ManagementClient custom fetch option", () => {
7979
const [calledUrl] = myFetchMock.mock.calls[0] as [string, RequestInit];
8080
expect(calledUrl).toContain(DOMAIN);
8181
});
82+
83+
it("uses the supplied mTLS fetch for Management API requests when useMTLS is set", async () => {
84+
// Client-credentials mode issues two calls through the supplied fetch:
85+
// (1) the token request to the oauth endpoint, (2) the api/v2 request.
86+
// Branch on URL so the token call gets a valid access_token and the
87+
// api/v2 call gets a users payload.
88+
const myFetchMock = jest.fn((url: string) => {
89+
if (String(url).includes("/oauth/token")) {
90+
return Promise.resolve(
91+
new Response(JSON.stringify({ access_token: "mtls-token", expires_in: 3600 }), {
92+
status: 200,
93+
headers: { "content-type": "application/json" },
94+
}),
95+
);
96+
}
97+
return Promise.resolve(
98+
new Response(JSON.stringify({ users: [], length: 0 }), {
99+
status: 200,
100+
headers: { "content-type": "application/json" },
101+
}),
102+
);
103+
});
104+
105+
const client = new ManagementClient({
106+
domain: DOMAIN,
107+
clientId: "test-client-id",
108+
clientSecret: "test-client-secret",
109+
useMTLS: true,
110+
fetch: myFetchMock as unknown as typeof fetch,
111+
});
112+
113+
await client.users.list();
114+
115+
// The mTLS-capable fetch must actually be invoked for the api/v2 call,
116+
// otherwise the client certificate is never presented on the request.
117+
const apiCall = myFetchMock.mock.calls.find(([u]) => !String(u).includes("/oauth/token"));
118+
expect(apiCall).toBeDefined();
119+
expect(String(apiCall![0])).toContain(DOMAIN);
120+
});
82121
});

‎src/management/tests/unit/token-provider.test.ts‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,4 +485,58 @@ describe("TokenProvider (raw fetch + jose)", () => {
485485
expect(err.message).toContain("token request failed");
486486
});
487487
});
488+
489+
// Helper: decode the Auth0-Client telemetry header (base64url JSON).
490+
// The jose mock's base64url.encode uses the real Buffer base64url encoding,
491+
// so Buffer decode round-trips it.
492+
function decodeTelemetry(header: string): { name: string; version: string } {
493+
return JSON.parse(Buffer.from(header, "base64url").toString());
494+
}
495+
496+
describe("TC-2.18 — telemetry:false omits Auth0-Client header", () => {
497+
it("should not send the auth0-client header when telemetry is disabled", async () => {
498+
fetchSpy.mockResolvedValue(makeOkResponse({ access_token: "no-telemetry-token", expires_in: 3600 }));
499+
500+
const tp = new TokenProvider({ ...opts, telemetry: false } as any);
501+
await tp.getAccessToken();
502+
503+
const callHeaders = (fetchSpy.mock.calls[0][1] as RequestInit).headers as Record<string, string>;
504+
expect(callHeaders["auth0-client"]).toBeUndefined();
505+
});
506+
});
507+
508+
describe("TC-2.19 — clientInfo override sets custom name/version in Auth0-Client header", () => {
509+
it("should encode the supplied clientInfo name and version", async () => {
510+
fetchSpy.mockResolvedValue(makeOkResponse({ access_token: "client-info-token", expires_in: 3600 }));
511+
512+
const tp = new TokenProvider({
513+
...opts,
514+
clientInfo: { name: "my-custom-sdk", version: "9.9.9" },
515+
} as any);
516+
await tp.getAccessToken();
517+
518+
const callHeaders = (fetchSpy.mock.calls[0][1] as RequestInit).headers as Record<string, string>;
519+
expect(callHeaders["auth0-client"]).toBeDefined();
520+
const decoded = decodeTelemetry(callHeaders["auth0-client"]);
521+
expect(decoded.name).toBe("my-custom-sdk");
522+
expect(decoded.version).toBe("9.9.9");
523+
});
524+
});
525+
526+
describe("TC-2.20 — default Auth0-Client header carries node-auth0 identity JSON", () => {
527+
it("should send a decodable auth0-client header with name and version", async () => {
528+
fetchSpy.mockResolvedValue(makeOkResponse({ access_token: "default-telemetry-token", expires_in: 3600 }));
529+
530+
const tp = new TokenProvider(opts);
531+
await tp.getAccessToken();
532+
533+
const callHeaders = (fetchSpy.mock.calls[0][1] as RequestInit).headers as Record<string, string>;
534+
expect(callHeaders["auth0-client"]).toBeDefined();
535+
const decoded = decodeTelemetry(callHeaders["auth0-client"]);
536+
expect(typeof decoded.name).toBe("string");
537+
expect(decoded.name.length).toBeGreaterThan(0);
538+
expect(typeof decoded.version).toBe("string");
539+
expect(decoded.version.length).toBeGreaterThan(0);
540+
});
541+
});
488542
});

‎tests/lib/export-surface.test.ts‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@ import { describe, it, expect } from "@jest/globals";
22
import * as auth0 from "../../src/index.js";
33

44
describe("Export Surface (v7.0.0)", () => {
5-
it("should NOT export AuthenticationClient", () => {
6-
expect((auth0 as any).AuthenticationClient).toBeUndefined();
7-
});
8-
9-
it("should NOT export UserInfoClient", () => {
10-
expect((auth0 as any).UserInfoClient).toBeUndefined();
11-
});
12-
135
it("should export ManagementClient", () => {
146
expect(auth0.ManagementClient).toBeDefined();
157
expect(typeof auth0.ManagementClient).toBe("function");

0 commit comments

Comments
 (0)