Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

## [Unreleased]

### 2026-03-24
- **Fix**: `auth login` 後に `NGSILD-Tenant` ヘッダーが付与されない問題を修正 — ログインレスポンスの `tenantId` を `service` として config に保存するようにした (#89)

## [0.8.0] - 2026-03-23

### 2026-03-23
Expand Down
10 changes: 7 additions & 3 deletions src/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ function createLoginCommand(): Command {

// Handle multi-tenant: show available tenants and prompt for selection
const availableTenants = data.availableTenants as TenantChoice[] | undefined;
const currentTenantId = data.tenantId as string | undefined;
let finalTenantId = data.tenantId as string | undefined;

if (availableTenants && availableTenants.length > 1 && !loginOpts.tenantId) {
const selectedTenantId = await promptTenantSelection(availableTenants, currentTenantId);
if (selectedTenantId && selectedTenantId !== currentTenantId) {
const selectedTenantId = await promptTenantSelection(availableTenants, finalTenantId);
if (selectedTenantId && selectedTenantId !== finalTenantId) {
// Re-login with selected tenant
const reloginResponse = await client.rawRequest("POST", "/auth/login", {
body: { email, password, tenantId: selectedTenantId },
Expand All @@ -133,6 +133,7 @@ function createLoginCommand(): Command {
}
token = newToken;
refreshToken = reloginData.refreshToken as string | undefined;
finalTenantId = selectedTenantId;
}
}

Expand All @@ -143,6 +144,9 @@ function createLoginCommand(): Command {
} else {
delete config.refreshToken;
}
if (finalTenantId) {
config.service = finalTenantId;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
saveConfig(config, globalOpts.profile);

printSuccess("Login successful. Token saved to config.");
Expand Down
34 changes: 31 additions & 3 deletions tests/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,34 @@ describe("auth commands", () => {
expect(saveConfig).toHaveBeenCalled();
});

it("saves tenantId as service when present in login response", async () => {
vi.mocked(isInteractive).mockReturnValue(true);
vi.mocked(promptEmail).mockResolvedValue("user@example.com");
vi.mocked(promptPassword).mockResolvedValue("pass123");
client.rawRequest.mockResolvedValue(
mockResponse({ accessToken: "tok", tenantId: "ed945710-fb96-4d17-811b-425abcb9b70e" }),
);
const program = makeProgram();
await runCommand(program, ["auth", "login"]);
expect(saveConfig).toHaveBeenCalledWith(
expect.objectContaining({ token: "tok", service: "ed945710-fb96-4d17-811b-425abcb9b70e" }),
"default",
);
});

it("does not set service when tenantId is absent from login response", async () => {
vi.mocked(isInteractive).mockReturnValue(true);
vi.mocked(promptEmail).mockResolvedValue("user@example.com");
vi.mocked(promptPassword).mockResolvedValue("pass123");
client.rawRequest.mockResolvedValue(
mockResponse({ accessToken: "tok" }),
);
const program = makeProgram();
await runCommand(program, ["auth", "login"]);
const savedConfig = vi.mocked(saveConfig).mock.calls[0][0] as Record<string, unknown>;
expect(savedConfig).not.toHaveProperty("service");
});

it("reads token from data.token when accessToken is not present", async () => {
vi.mocked(isInteractive).mockReturnValue(true);
vi.mocked(promptEmail).mockResolvedValue("user@example.com");
Expand Down Expand Up @@ -356,7 +384,7 @@ describe("auth commands", () => {
await runCommand(program, ["auth", "login"]);
expect(promptTenantSelection).toHaveBeenCalledWith(tenants, "city_a");
expect(saveConfig).toHaveBeenCalledWith(
expect.objectContaining({ token: "tok" }),
expect.objectContaining({ token: "tok", service: "city_a" }),
"default",
);
});
Expand All @@ -382,7 +410,7 @@ describe("auth commands", () => {
skipTenantHeader: true,
});
expect(saveConfig).toHaveBeenCalledWith(
expect.objectContaining({ token: "tok-b", refreshToken: "ref-b" }),
expect.objectContaining({ token: "tok-b", refreshToken: "ref-b", service: "city_b" }),
"default",
);
});
Expand Down Expand Up @@ -445,7 +473,7 @@ describe("auth commands", () => {
// Should not re-login since selectedTenantId === currentTenantId
expect(client.rawRequest).toHaveBeenCalledTimes(1);
expect(saveConfig).toHaveBeenCalledWith(
expect.objectContaining({ token: "tok-a" }),
expect.objectContaining({ token: "tok-a", service: "city_a" }),
"default",
);
});
Expand Down
Loading