Skip to content

Commit

Permalink
Feature/basic auth (#608)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasio authored Sep 27, 2023
1 parent 466d27b commit 15189a0
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-cheetahs-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@headstartwp/core": patch
---

Adding support for basic auth
19 changes: 19 additions & 0 deletions docs/documentation/06-WordPress Integration/basic-auth.md
Original file line number Diff line number Diff line change
@@ -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
6 changes: 0 additions & 6 deletions packages/core/src/data/api/fetch-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
29 changes: 27 additions & 2 deletions packages/core/src/data/strategies/AbstractFetchStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,27 @@ export abstract class AbstractFetchStrategy<E, Params extends EndpointParams, R
};
}

getAuthHeader(options: Partial<FetchOptions> = {}) {
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
*
Expand All @@ -245,9 +266,13 @@ export abstract class AbstractFetchStrategy<E, Params extends EndpointParams, R
const { burstCache = false } = options;

const args = {};
if (options.bearerToken) {

const authHeader = this.getAuthHeader(options);
if (authHeader) {
// @ts-expect-error
args.headers = { Authorization: `Bearer ${options.bearerToken}` };
args.headers = {
Authorization: authHeader,
};
}

const result = await apiGet(`${this.baseURL}${url}`, args, burstCache);
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/data/strategies/SinglePostFetchStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,14 +279,16 @@ export class SinglePostFetchStrategy<
options.bearerToken = params.authToken;
}

const authHeader = this.getAuthHeader(options);

let error;
if (params.revision && params.id) {
try {
const response = await apiGet(
`${this.baseURL}${this.getEndpoint()}/revisions?per_page=1`,
{
headers: {
Authorization: `Bearer ${options.bearerToken}`,
Authorization: authHeader,
},
},
burstCache,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,4 +681,66 @@ describe('SinglePostFetchStrategy', () => {
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,
);
});
});

0 comments on commit 15189a0

Please sign in to comment.