Skip to content

Commit f657758

Browse files
authored
fix(channel): default insecure to false, warn on token+plaintext
- Flips `ClientOptions.insecure` default to `false` so TLS is used out of the box; plaintext requires explicit `insecure: true`. - Logs a warning when `insecure: true` is combined with a bearer token, since the token would be transmitted in cleartext. - Adds test coverage for the warning path and documents the breaking change in CHANGELOG. Closes #43 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent e3076f1 commit f657758

4 files changed

Lines changed: 40 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

7+
## [Unreleased]
8+
9+
### Changed
10+
11+
- **Breaking:** `ClientOptions.insecure` now defaults to `false` (TLS). Previously defaulted to `true` (plaintext). Connections to TLS endpoints now work correctly out of the box; plaintext requires explicit `insecure: true`.
12+
13+
### Added
14+
15+
- Warning logged when `insecure: true` is set alongside a bearer token, since the token would be transmitted in cleartext.
16+
717
## [0.2.0-alpha.1] - 2026-04-16
818

919
### Changed

src/channel.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,22 @@ import type { ClientOptions } from "./types.js";
1010
/**
1111
* Create gRPC channel credentials based on client options.
1212
*
13-
* - If `insecure` is true (default), returns insecure credentials (plaintext).
14-
* - Otherwise, returns TLS credentials.
13+
* - If `insecure` is true, returns insecure credentials (plaintext).
14+
* - Otherwise (default), returns TLS credentials.
15+
*
16+
* Logs a warning when plaintext is enabled with a token configured,
17+
* since the bearer token would be transmitted in cleartext.
1518
*/
1619
export function createChannel(options: ClientOptions): ChannelCredentials {
17-
const insecure = options.insecure ?? true;
20+
const insecure = options.insecure ?? false;
1821
if (insecure) {
22+
if (options.token) {
23+
console.warn(
24+
"[decree] WARNING: insecure=true with a bearer token configured — " +
25+
"the token will be transmitted in cleartext. " +
26+
"Set insecure=false (or omit it) to use TLS.",
27+
);
28+
}
1929
return credentials.createInsecure();
2030
}
2131
return credentials.createSsl();

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export interface ClientOptions {
5959
readonly tenantId?: string;
6060
/** Bearer token. When set, metadata headers are not sent. */
6161
readonly token?: string;
62-
/** Use plaintext (no TLS). Default: true. */
62+
/** Use plaintext (no TLS). Default: false. Set to true only for local/dev servers without TLS. */
6363
readonly insecure?: boolean;
6464
/** Default per-RPC timeout in milliseconds. Default: 10000. */
6565
readonly timeout?: number;

test/client.test.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,14 +421,27 @@ describe("ConfigClient", () => {
421421
});
422422

423423
describe("TLS channel", () => {
424-
it("creates insecure channel by default", () => {
424+
it("creates TLS channel by default", () => {
425425
const c = new ConfigClient("localhost:9090", { retry: false });
426426
c.close();
427427
});
428428

429-
it("creates TLS channel when insecure is false", () => {
430-
const c = new ConfigClient("localhost:9090", { insecure: false, retry: false });
429+
it("creates insecure channel when insecure is true", () => {
430+
const c = new ConfigClient("localhost:9090", { insecure: true, retry: false });
431431
c.close();
432432
});
433+
434+
it("warns when insecure is true and a token is configured", () => {
435+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
436+
const c = new ConfigClient("localhost:9090", {
437+
insecure: true,
438+
token: "secret",
439+
retry: false,
440+
});
441+
c.close();
442+
expect(warn).toHaveBeenCalledOnce();
443+
expect(warn.mock.calls[0][0]).toContain("cleartext");
444+
warn.mockRestore();
445+
});
433446
});
434447
});

0 commit comments

Comments
 (0)