diff --git a/packages/@n8n/nodes-langchain/nodes/trigger/ChatTrigger/templates.ts b/packages/@n8n/nodes-langchain/nodes/trigger/ChatTrigger/templates.ts index d5935d6fad..9c7f7f0301 100644 --- a/packages/@n8n/nodes-langchain/nodes/trigger/ChatTrigger/templates.ts +++ b/packages/@n8n/nodes-langchain/nodes/trigger/ChatTrigger/templates.ts @@ -41,7 +41,7 @@ export function createPage({ ? loadPreviousSession : 'notSupported'; - return ` + return ` @@ -60,7 +60,8 @@ export function createPage({ if (authentication === 'n8nUserAuth') { try { const response = await fetch('/rest/login', { - method: 'GET' + method: 'GET', + headers: { 'browser-id': localStorage.getItem('n8n-browserId') } }); if (response.status !== 200) { diff --git a/packages/cli/src/auth/auth.service.ts b/packages/cli/src/auth/auth.service.ts index d7227fd063..f8e332cbfe 100644 --- a/packages/cli/src/auth/auth.service.ts +++ b/packages/cli/src/auth/auth.service.ts @@ -33,7 +33,16 @@ interface PasswordResetToken { hash: string; } -const pushEndpoint = `/${config.get('endpoints.rest')}/push`; +const restEndpoint = config.get('endpoints.rest'); +// The browser-id check needs to be skipped on these endpoints +const skipBrowserIdCheckEndpoints = [ + // we need to exclude push endpoint because we can't send custom header on websocket requests + // TODO: Implement a custom handshake for push, to avoid having to send any data on querystring or headers + `/${restEndpoint}/push`, + + // We need to exclude binary-data downloading endpoint because we can't send custom headers on `` tags + `/${restEndpoint}/binary-data`, +]; @Service() export class AuthService { @@ -120,9 +129,7 @@ export class AuthService { // or, If the email or password has been updated jwtPayload.hash !== this.createJWTHash(user) || // If the token was issued for another browser session - // NOTE: we need to exclude push endpoint from this check because we can't send custom header on websocket requests - // TODO: Implement a custom handshake for push, to avoid having to send any data on querystring or headers - (req.baseUrl !== pushEndpoint && + (!skipBrowserIdCheckEndpoints.includes(req.baseUrl) && jwtPayload.browserId && (!req.browserId || jwtPayload.browserId !== this.hash(req.browserId))) ) { diff --git a/packages/cli/test/integration/shared/utils/testServer.ts b/packages/cli/test/integration/shared/utils/testServer.ts index 829fd0214c..4d94c56595 100644 --- a/packages/cli/test/integration/shared/utils/testServer.ts +++ b/packages/cli/test/integration/shared/utils/testServer.ts @@ -22,6 +22,7 @@ import { PUBLIC_API_REST_PATH_SEGMENT, REST_PATH_SEGMENT } from '../constants'; import type { SetupProps, TestServer } from '../types'; import { LicenseMocker } from '../license'; import { AuthService } from '@/auth/auth.service'; +import type { APIRequest } from '@/requests'; /** * Plugin to prefix a path segment into a request URL pathname. @@ -43,11 +44,12 @@ function prefix(pathSegment: string) { }; } +const browserId = 'test-browser-id'; function createAgent(app: express.Application, options?: { auth: boolean; user: User }) { const agent = request.agent(app); void agent.use(prefix(REST_PATH_SEGMENT)); if (options?.auth && options?.user) { - const token = Container.get(AuthService).issueJWT(options.user); + const token = Container.get(AuthService).issueJWT(options.user, browserId); agent.jar.setCookie(`${AUTH_COOKIE_NAME}=${token}`); } return agent; @@ -73,6 +75,10 @@ export const setupTestServer = ({ const app = express(); app.use(rawBodyReader); app.use(cookieParser()); + app.use((req: APIRequest, _, next) => { + req.browserId = browserId; + next(); + }); // Mock all telemetry and logging mockInstance(Logger);