diff --git a/src/connection/grpc.ts b/src/connection/grpc.ts index e40f8ece..4f02350f 100644 --- a/src/connection/grpc.ts +++ b/src/connection/grpc.ts @@ -194,7 +194,7 @@ export const grpcClient = (config: GrpcConnectionParams & { grpcMaxMessageLength Batcher.use( client, collection, - new Metadata(bearerToken ? { ...config.headers, authorization: bearerToken } : config.headers), + getMetadataWithEmbeddingServiceAuth(config, bearerToken), config.timeout?.insert || 90, consistencyLevel, tenant @@ -223,7 +223,7 @@ export const grpcClient = (config: GrpcConnectionParams & { grpcMaxMessageLength Searcher.use( client, collection, - new Metadata(bearerToken ? { ...config.headers, authorization: bearerToken } : config.headers), + getMetadataWithEmbeddingServiceAuth(config, bearerToken), config.timeout?.query || 30, consistencyLevel, tenant @@ -237,3 +237,16 @@ export const grpcClient = (config: GrpcConnectionParams & { grpcMaxMessageLength ), }; }; + +const getMetadataWithEmbeddingServiceAuth = (config: GrpcConnectionParams, bearerToken?: string) => + new Metadata( + bearerToken + ? { + ...config.headers, + authorization: bearerToken, + 'X-Weaviate-Cluster-Url': config.host, + // keeping for backwards compatibility for older clusters for now. On newer clusters, Embedding Service reuses Authorization header. + 'X-Weaviate-Api-Key': bearerToken, + } + : config.headers + ); diff --git a/src/connection/helpers.test.ts b/src/connection/helpers.test.ts index 97f6049b..7e0f4276 100644 --- a/src/connection/helpers.test.ts +++ b/src/connection/helpers.test.ts @@ -1,5 +1,4 @@ import weaviate from '../index.js'; -import { connectToWeaviateCloud } from './helpers.js'; const WCD_URL = 'https://piblpmmdsiknacjnm1ltla.c1.europe-west3.gcp.weaviate.cloud'; const WCD_KEY = 'cy4ua772mBlMdfw3YnclqAWzFhQt0RLIN0sl'; @@ -30,57 +29,4 @@ describe('Testing of the connection helper methods', () => { throw new Error('it should not have errord: ' + e); }); }); - - describe('adds Weaviate Embedding Service headers', () => { - it('to empty headers', async () => { - const clientMakerMock = jest.fn().mockResolvedValue(undefined); - - await connectToWeaviateCloud(WCD_URL, clientMakerMock, { - authCredentials: new weaviate.ApiKey(WCD_KEY), - }); - - expect(clientMakerMock.mock.calls[0][0].headers).toEqual({ - 'X-Weaviate-Api-Key': WCD_KEY, - 'X-Weaviate-Cluster-Url': WCD_URL, - }); - }); - - it('to existing headers', async () => { - const clientMakerMock = jest.fn().mockResolvedValue(undefined); - - await connectToWeaviateCloud(WCD_URL, clientMakerMock, { - authCredentials: new weaviate.ApiKey(WCD_KEY), - headers: { existingHeader: 'existingValue' }, - }); - - expect(clientMakerMock.mock.calls[0][0].headers).toEqual({ - existingHeader: 'existingValue', - 'X-Weaviate-Api-Key': WCD_KEY, - 'X-Weaviate-Cluster-Url': WCD_URL, - }); - }); - }); - - describe('does not add Weaviate Embedding Service headers when not using API key', () => { - it('to empty headers', async () => { - const clientMakerMock = jest.fn().mockResolvedValue(undefined); - - await connectToWeaviateCloud(WCD_URL, clientMakerMock, { - authCredentials: new weaviate.AuthUserPasswordCredentials({ username: 'test' }), - }); - - expect(clientMakerMock.mock.calls[0][0].headers).toBe(undefined); - }); - - it('to existing headers', async () => { - const clientMakerMock = jest.fn().mockResolvedValue(undefined); - - await connectToWeaviateCloud(WCD_URL, clientMakerMock, { - authCredentials: new weaviate.AuthUserPasswordCredentials({ username: 'test' }), - headers: { existingHeader: 'existingValue' }, - }); - - expect(clientMakerMock.mock.calls[0][0].headers).toEqual({ existingHeader: 'existingValue' }); - }); - }); }); diff --git a/src/connection/helpers.ts b/src/connection/helpers.ts index e5b598ca..5deb66ab 100644 --- a/src/connection/helpers.ts +++ b/src/connection/helpers.ts @@ -1,6 +1,6 @@ import { WeaviateStartUpError } from '../errors.js'; import { ClientParams, WeaviateClient } from '../index.js'; -import { AuthCredentials, isApiKey, mapApiKey } from './auth.js'; +import { AuthCredentials } from './auth.js'; import { ProxiesParams, TimeoutParams } from './http.js'; /** The options available to the `weaviate.connectToWeaviateCloud` method. */ @@ -102,7 +102,7 @@ export function connectToWeaviateCloud( }, }, auth, - headers: addWeaviateEmbeddingServiceHeaders(clusterURL, auth, headers), + headers: options?.headers, ...rest, }).catch((e) => { throw new WeaviateStartUpError(`Weaviate failed to startup with message: ${e.message}`); @@ -169,19 +169,3 @@ export function connectToCustom( throw new WeaviateStartUpError(`Weaviate failed to startup with message: ${e.message}`); }); } - -function addWeaviateEmbeddingServiceHeaders( - clusterURL: string, - creds?: AuthCredentials, - headers?: Record -) { - if (!isApiKey(creds)) { - return headers; - } - - return { - ...headers, - 'X-Weaviate-Api-Key': mapApiKey(creds).apiKey, - 'X-Weaviate-Cluster-Url': clusterURL, - }; -} diff --git a/src/connection/http.ts b/src/connection/http.ts index c18efb58..5250d930 100644 --- a/src/connection/http.ts +++ b/src/connection/http.ts @@ -243,11 +243,11 @@ export const httpClient = (config: InternalConnectionParams): HttpClient => { headers: { ...config.headers, 'content-type': 'application/json', + ...getAuthHeaders(config, bearerToken), }, body: JSON.stringify(payload), agent: config.agent, }; - addAuthHeaderIfNeeded(request, bearerToken); return fetchWithTimeout(url(path), config.timeout?.insert || 90, request).then( checkStatus(expectReturnContent) ); @@ -263,11 +263,11 @@ export const httpClient = (config: InternalConnectionParams): HttpClient => { headers: { ...config.headers, 'content-type': 'application/json', + ...getAuthHeaders(config, bearerToken), }, body: JSON.stringify(payload), agent: config.agent, }; - addAuthHeaderIfNeeded(request, bearerToken); return fetchWithTimeout(url(path), config.timeout?.insert || 90, request).then( checkStatus(expectReturnContent) ); @@ -278,11 +278,11 @@ export const httpClient = (config: InternalConnectionParams): HttpClient => { headers: { ...config.headers, 'content-type': 'application/json', + ...getAuthHeaders(config, bearerToken), }, body: JSON.stringify(payload), agent: config.agent, }; - addAuthHeaderIfNeeded(request, bearerToken); return fetchWithTimeout(url(path), config.timeout?.insert || 90, request).then(checkStatus(false)); }, delete: (path: string, payload: B | null = null, expectReturnContent = false, bearerToken = '') => { @@ -291,11 +291,11 @@ export const httpClient = (config: InternalConnectionParams): HttpClient => { headers: { ...config.headers, 'content-type': 'application/json', + ...getAuthHeaders(config, bearerToken), }, body: payload ? JSON.stringify(payload) : undefined, agent: config.agent, }; - addAuthHeaderIfNeeded(request, bearerToken); return fetchWithTimeout(url(path), config.timeout?.insert || 90, request).then( checkStatus(expectReturnContent) ); @@ -306,11 +306,11 @@ export const httpClient = (config: InternalConnectionParams): HttpClient => { headers: { ...config.headers, 'content-type': 'application/json', + ...getAuthHeaders(config, bearerToken), }, body: payload ? JSON.stringify(payload) : undefined, agent: config.agent, }; - addAuthHeaderIfNeeded(request, bearerToken); return fetchWithTimeout(url(path), config.timeout?.query || 30, request).then( handleHeadResponse(false) ); @@ -320,10 +320,10 @@ export const httpClient = (config: InternalConnectionParams): HttpClient => { method: 'GET', headers: { ...config.headers, + ...getAuthHeaders(config, bearerToken), }, agent: config.agent, }; - addAuthHeaderIfNeeded(request, bearerToken); return fetchWithTimeout(url(path), config.timeout?.query || 30, request).then( checkStatus(expectReturnContent) ); @@ -334,10 +334,10 @@ export const httpClient = (config: InternalConnectionParams): HttpClient => { method: 'GET', headers: { ...config.headers, + ...getAuthHeaders(config, bearerToken), }, agent: config.agent, }; - addAuthHeaderIfNeeded(request, bearerToken); return fetchWithTimeout(url(path), config.timeout?.query || 30, request); }, externalGet: (externalUrl: string) => { @@ -406,8 +406,12 @@ const handleHeadResponse = return checkStatus(expectResponseBody)(res); }; -function addAuthHeaderIfNeeded(request: any, bearerToken: string) { - if (bearerToken !== '') { - request.headers.Authorization = `Bearer ${bearerToken}`; - } -} +const getAuthHeaders = (config: InternalConnectionParams, bearerToken: string) => + bearerToken + ? { + Authorization: `Bearer ${bearerToken}`, + 'X-Weaviate-Cluster-Url': config.host, + // keeping for backwards compatibility for older clusters for now. On newer clusters, Embedding Service reuses Authorization header. + 'X-Weaviate-Api-Key': bearerToken, + } + : undefined;