Skip to content

Commit e5ed855

Browse files
committed
fix: use user-id header instead of x-user-id for Link Service
- Change SessionInterceptor to use user-id header (Link Service expects this) - Update buildCallOptions to send only user-id header - Remove x-user-id header completely - Update SessionInterceptor test to check for user-id header - Fixes session_interceptor: user-id missing error
1 parent 7212338 commit e5ed855

File tree

3 files changed

+16
-18
lines changed

3 files changed

+16
-18
lines changed

boundaries/proxy/src/infrastructure/adapters/LinkServiceConnectAdapter.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ export class LinkServiceConnectAdapter implements ILinkServiceAdapter {
114114
signal: AbortSignal.timeout(this.externalServicesConfig.requestTimeout),
115115
};
116116

117-
// According to ADR 42: pass user_id via x-user-id header
118-
// If userId is provided, use it; otherwise interceptor will use serviceUserId or "anonymous"
119-
if (userId) {
120-
options.header = {
121-
"x-user-id": userId === "anonymous" ? "anonymous" : userId,
122-
};
123-
}
117+
// Link Service expects "user-id" in metadata (session_interceptor checks for it)
118+
// Always set header - if userId provided, use it; otherwise pass "anonymous"
119+
// SessionInterceptor will use serviceUserId as fallback if header is missing
120+
const userIdValue = userId && userId !== "anonymous" ? userId : "anonymous";
121+
options.header = {
122+
"user-id": userIdValue,
123+
};
124124

125125
return options;
126126
}

boundaries/proxy/src/infrastructure/adapters/connect/interceptors/SessionInterceptor.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
import type { Interceptor } from "@connectrpc/connect";
22

3-
const X_USER_ID_HEADER = "x-user-id";
3+
const USER_ID_HEADER = "user-id";
44

55
/**
66
* Connect interceptor that ensures Link Service always receives a user-id metadata.
7-
* According to ADR 42: Proxy passes user_id via x-user-id header.
7+
* Link Service expects "user-id" in metadata (session_interceptor checks for it).
88
* Link Service uses this to check private link access via Kratos Admin API.
99
*
10-
* This interceptor sets a default value (serviceUserId) if x-user-id is not already set
10+
* This interceptor sets a default value (serviceUserId) if user-id is not already set
1111
* in the request headers. The actual userId from Kratos session is set via callOptions.header
1212
* in LinkServiceConnectAdapter.getLinkByHash().
1313
*
1414
* @param serviceUserId - stable identifier for proxy service account (fallback).
1515
*/
16-
export function createSessionInterceptor(
17-
serviceUserId: string
18-
): Interceptor {
16+
export function createSessionInterceptor(serviceUserId: string): Interceptor {
1917
if (!serviceUserId || !serviceUserId.trim()) {
2018
throw new Error(
2119
"SERVICE_USER_ID is required to call Link Service. Provide non-empty value."
@@ -25,10 +23,10 @@ export function createSessionInterceptor(
2523
const normalizedServiceUserId = serviceUserId.trim();
2624

2725
return (next) => async (req) => {
28-
// Set default x-user-id if not already set (from callOptions.header)
26+
// Set default user-id if not already set (from callOptions.header)
2927
// This ensures backward compatibility and provides a fallback
30-
if (!req.header.get(X_USER_ID_HEADER)) {
31-
req.header.set(X_USER_ID_HEADER, normalizedServiceUserId);
28+
if (!req.header.get(USER_ID_HEADER)) {
29+
req.header.set(USER_ID_HEADER, normalizedServiceUserId);
3230
}
3331

3432
return next(req);

boundaries/proxy/src/infrastructure/adapters/connect/interceptors/__tests__/SessionInterceptor.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
22
import { createSessionInterceptor } from "../SessionInterceptor.js";
33

44
describe("createSessionInterceptor", () => {
5-
it("sets x-user-id header on outgoing request", async () => {
5+
it("sets user-id header on outgoing request", async () => {
66
const interceptor = createSessionInterceptor("proxy-user");
77
const headerMap = new Map<string, string>();
88
const mockHeader = {
@@ -22,7 +22,7 @@ describe("createSessionInterceptor", () => {
2222

2323
await interceptor(next)(request);
2424

25-
expect(request.header.get("x-user-id")).toBe("proxy-user");
25+
expect(request.header.get("user-id")).toBe("proxy-user");
2626
});
2727

2828
it("throws when service user id is empty", () => {

0 commit comments

Comments
 (0)