From 15189a031c5923c102e05be155145cf5a22e5887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Wed, 27 Sep 2023 10:58:14 -0300 Subject: [PATCH] Feature/basic auth (#608) --- .changeset/eighty-cheetahs-wonder.md | 5 ++ .../06-WordPress Integration/basic-auth.md | 19 ++++++ packages/core/src/data/api/fetch-utils.ts | 6 -- .../data/strategies/AbstractFetchStrategy.ts | 29 ++++++++- .../strategies/SinglePostFetchStrategy.ts | 4 +- .../__tests__/SinglePostFetchStrategy.ts | 62 +++++++++++++++++++ 6 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 .changeset/eighty-cheetahs-wonder.md create mode 100644 docs/documentation/06-WordPress Integration/basic-auth.md diff --git a/.changeset/eighty-cheetahs-wonder.md b/.changeset/eighty-cheetahs-wonder.md new file mode 100644 index 000000000..446963a93 --- /dev/null +++ b/.changeset/eighty-cheetahs-wonder.md @@ -0,0 +1,5 @@ +--- +"@headstartwp/core": patch +--- + +Adding support for basic auth diff --git a/docs/documentation/06-WordPress Integration/basic-auth.md b/docs/documentation/06-WordPress Integration/basic-auth.md new file mode 100644 index 000000000..cc9f6d63e --- /dev/null +++ b/docs/documentation/06-WordPress Integration/basic-auth.md @@ -0,0 +1,19 @@ +--- +slug: /wordpress-integration/basic-auth +--- + +# Basic Auth + +If WordPress is protected by Basic Auth (which is common during development) you can tell HeadstartWP the basic auth creds so that all +REST API requests include them. To do so, simply add the following env variables: + +``` +WP_BASIC_AUTH_USERNAME=username +WP_BASIC_AUTH_PASSWORD=password +``` + +:::caution +The above env variables will only be accessible server-side and therefore any client-side requests made directly to WordPress will fail. This happens because Next.js only includes env variables prefixed with `NEXT_PUBLIC_` in the browser bundle. + +If you want your client-side requests to work, prefix the above variables with `NEXT_PUBLIC_`. But note that the basic auth creds will be leaked to the public. +:::caution diff --git a/packages/core/src/data/api/fetch-utils.ts b/packages/core/src/data/api/fetch-utils.ts index b249b49d8..141d2b08e 100644 --- a/packages/core/src/data/api/fetch-utils.ts +++ b/packages/core/src/data/api/fetch-utils.ts @@ -48,12 +48,6 @@ export const apiGet = async ( args: { [index: string]: any } = {}, burstCache = false, ) => { - const headers = getAuthHeader(); - - if (headers) { - args.headers = headers; - } - const queryArgs = burstCache ? { cacheTime: new Date().getTime(), diff --git a/packages/core/src/data/strategies/AbstractFetchStrategy.ts b/packages/core/src/data/strategies/AbstractFetchStrategy.ts index 6d3136fc3..dd3657e8e 100644 --- a/packages/core/src/data/strategies/AbstractFetchStrategy.ts +++ b/packages/core/src/data/strategies/AbstractFetchStrategy.ts @@ -224,6 +224,27 @@ export abstract class AbstractFetchStrategy = {}) { + let bearerAuthHeader = ''; + if (options.bearerToken) { + bearerAuthHeader = `Bearer ${options.bearerToken}`; + } + + const basicAuthUsername = + process.env.WP_BASIC_AUTH_USERNAME ?? process.env.NEXT_PUBLIC_WP_BASIC_AUTH_USERNAME; + const basicAuthPassword = + process.env.WP_BASIC_AUTH_PASSWORD ?? process.env.NEXT_PUBLIC_WP_BASIC_AUTH_PASSWORD; + + if (basicAuthUsername && basicAuthPassword) { + const basicAuth = `Basic ${btoa(`${basicAuthUsername}:${basicAuthPassword}`)}`; + if (bearerAuthHeader) { + return `${basicAuth}, ${bearerAuthHeader}`; + } + return basicAuth; + } + return bearerAuthHeader; + } + /** * The default fetcher function * @@ -245,9 +266,13 @@ export abstract class AbstractFetchStrategy { result: {}, }); }); + + it('handles basic auth', async () => { + const samplePost = { title: 'test', id: 1, link: '/2021/10/post-name' }; + const sampleHeaders = { + 'x-wp-totalpages': 1, + 'x-wp-total': 1, + }; + + apiGetMock.mockResolvedValue({ + headers: sampleHeaders, + json: [samplePost], + }); + + process.env.WP_BASIC_AUTH_PASSWORD = 'test'; + process.env.WP_BASIC_AUTH_USERNAME = 'admin'; + + const params = fetchStrategy.getParamsFromURL('/2021/10/post-name'); + await fetchStrategy.fetcher(fetchStrategy.buildEndpointURL(params), params); + + expect(apiGetMock).toHaveBeenNthCalledWith( + 1, + '/wp-json/wp/v2/posts?slug=post-name', + { + headers: { + Authorization: 'Basic YWRtaW46dGVzdA==', + }, + }, + false, + ); + }); + + it('handles basic auth and bearer token', async () => { + const samplePost = { title: 'test', id: 1, link: '/2021/10/post-name' }; + const sampleHeaders = { + 'x-wp-totalpages': 1, + 'x-wp-total': 1, + }; + + apiGetMock.mockResolvedValue({ + headers: sampleHeaders, + json: [samplePost], + }); + + process.env.WP_BASIC_AUTH_PASSWORD = 'test'; + process.env.WP_BASIC_AUTH_USERNAME = 'admin'; + + const params = fetchStrategy.getParamsFromURL('/2021/10/post-name'); + await fetchStrategy.fetcher(fetchStrategy.buildEndpointURL(params), params, { + bearerToken: 'bearer token', + }); + + expect(apiGetMock).toHaveBeenNthCalledWith( + 1, + '/wp-json/wp/v2/posts?slug=post-name', + { + headers: { + Authorization: 'Basic YWRtaW46dGVzdA==, Bearer bearer token', + }, + }, + false, + ); + }); });