Skip to content

Commit 5581933

Browse files
committed
fix(next-drupal): allow clientId/Secret in getAccessToken() params
1 parent fda9709 commit 5581933

File tree

4 files changed

+64
-45
lines changed

4 files changed

+64
-45
lines changed

packages/next-drupal/src/client.ts

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
import type {
1313
AccessToken,
1414
BaseUrl,
15+
DrupalClientAuth,
1516
DrupalClientAuthAccessToken,
1617
DrupalClientAuthClientIdSecret,
1718
DrupalClientAuthUsernamePassword,
@@ -53,25 +54,28 @@ const DEFAULT_HEADERS = {
5354
}
5455

5556
function isBasicAuth(
56-
auth: DrupalClientOptions["auth"]
57+
auth: DrupalClientAuth
5758
): auth is DrupalClientAuthUsernamePassword {
5859
return (
59-
(auth as DrupalClientAuthUsernamePassword)?.username !== undefined ||
60+
(auth as DrupalClientAuthUsernamePassword)?.username !== undefined &&
6061
(auth as DrupalClientAuthUsernamePassword)?.password !== undefined
6162
)
6263
}
6364

6465
function isAccessTokenAuth(
65-
auth: DrupalClientOptions["auth"]
66+
auth: DrupalClientAuth
6667
): auth is DrupalClientAuthAccessToken {
67-
return (auth as DrupalClientAuthAccessToken)?.access_token !== undefined
68+
return (
69+
(auth as DrupalClientAuthAccessToken)?.access_token !== undefined &&
70+
(auth as DrupalClientAuthAccessToken)?.token_type !== undefined
71+
)
6872
}
6973

7074
function isClientIdSecretAuth(
71-
auth: DrupalClient["auth"]
75+
auth: DrupalClientAuth
7276
): auth is DrupalClientAuthClientIdSecret {
7377
return (
74-
(auth as DrupalClientAuthClientIdSecret)?.clientId !== undefined ||
78+
(auth as DrupalClientAuthClientIdSecret)?.clientId !== undefined &&
7579
(auth as DrupalClientAuthClientIdSecret)?.clientSecret !== undefined
7680
)
7781
}
@@ -177,31 +181,47 @@ export class DrupalClient {
177181

178182
set auth(auth: DrupalClientOptions["auth"]) {
179183
if (typeof auth === "object") {
180-
if (isBasicAuth(auth)) {
181-
if (!auth.username || !auth.password) {
184+
const checkUsernamePassword = auth as DrupalClientAuthUsernamePassword
185+
const checkAccessToken = auth as DrupalClientAuthAccessToken
186+
const checkClientIdSecret = auth as DrupalClientAuthClientIdSecret
187+
188+
if (
189+
checkUsernamePassword.username !== undefined ||
190+
checkUsernamePassword.password !== undefined
191+
) {
192+
if (
193+
!checkUsernamePassword.username ||
194+
!checkUsernamePassword.password
195+
) {
182196
throw new Error(
183197
`'username' and 'password' are required for auth. See https://next-drupal.org/docs/client/auth`
184198
)
185199
}
186-
} else if (isAccessTokenAuth(auth)) {
187-
if (!auth.access_token || !auth.token_type) {
200+
} else if (
201+
checkAccessToken.access_token !== undefined ||
202+
checkAccessToken.token_type !== undefined
203+
) {
204+
if (!checkAccessToken.access_token || !checkAccessToken.token_type) {
188205
throw new Error(
189206
`'access_token' and 'token_type' are required for auth. See https://next-drupal.org/docs/client/auth`
190207
)
191208
}
192-
} else if (!auth.clientId || !auth.clientSecret) {
209+
} else if (
210+
!checkClientIdSecret.clientId ||
211+
!checkClientIdSecret.clientSecret
212+
) {
193213
throw new Error(
194214
`'clientId' and 'clientSecret' are required for auth. See https://next-drupal.org/docs/client/auth`
195215
)
196216
}
197217

198-
auth = {
199-
url: DEFAULT_AUTH_URL,
218+
this._auth = {
219+
...(isClientIdSecretAuth(auth) ? { url: DEFAULT_AUTH_URL } : {}),
200220
...auth,
201221
}
222+
} else {
223+
this._auth = auth
202224
}
203-
204-
this._auth = auth
205225
}
206226

207227
set headers(value: DrupalClientOptions["headers"]) {
@@ -1356,26 +1376,25 @@ export class DrupalClient {
13561376
return this.accessToken
13571377
}
13581378

1359-
if (!opts?.clientId || !opts?.clientSecret) {
1360-
if (typeof this._auth === "undefined") {
1361-
throw new Error(
1362-
"auth is not configured. See https://next-drupal.org/docs/client/auth"
1363-
)
1379+
let auth: DrupalClientAuthClientIdSecret
1380+
if (isClientIdSecretAuth(opts)) {
1381+
auth = {
1382+
url: DEFAULT_AUTH_URL,
1383+
...opts,
13641384
}
1365-
}
1366-
1367-
if (
1368-
!isClientIdSecretAuth(this._auth) ||
1369-
(opts && !isClientIdSecretAuth(opts))
1370-
) {
1385+
} else if (isClientIdSecretAuth(this._auth)) {
1386+
auth = this._auth
1387+
} else if (typeof this._auth === "undefined") {
1388+
throw new Error(
1389+
"auth is not configured. See https://next-drupal.org/docs/client/auth"
1390+
)
1391+
} else {
13711392
throw new Error(
13721393
`'clientId' and 'clientSecret' required. See https://next-drupal.org/docs/client/auth`
13731394
)
13741395
}
13751396

1376-
const clientId = opts?.clientId || this._auth.clientId
1377-
const clientSecret = opts?.clientSecret || this._auth.clientSecret
1378-
const url = this.buildUrl(opts?.url || this._auth.url)
1397+
const url = this.buildUrl(auth.url)
13791398

13801399
if (
13811400
this.accessTokenScope === opts?.scope &&
@@ -1388,7 +1407,9 @@ export class DrupalClient {
13881407

13891408
this.debug(`Fetching new access token.`)
13901409

1391-
const basic = Buffer.from(`${clientId}:${clientSecret}`).toString("base64")
1410+
const basic = Buffer.from(`${auth.clientId}:${auth.clientSecret}`).toString(
1411+
"base64"
1412+
)
13921413

13931414
let body = `grant_type=client_credentials`
13941415

packages/next-drupal/tests/DrupalClient/constructor.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Jsona } from "jsona"
33
import { DrupalClient } from "../../src"
44
import { DEBUG_MESSAGE_PREFIX, logger as defaultLogger } from "../../src/logger"
55
import { BASE_URL } from "../utils"
6-
import type { Logger } from "../../src"
6+
import type { DrupalClientAuth, Logger } from "../../src"
77

88
afterEach(() => {
99
jest.restoreAllMocks()
@@ -106,7 +106,7 @@ describe("options parameter", () => {
106106
})
107107

108108
test("sets the auth credentials", () => {
109-
const auth: DrupalClient["auth"] = {
109+
const auth: DrupalClientAuth = {
110110
username: "example",
111111
password: "pw",
112112
}
@@ -115,7 +115,6 @@ describe("options parameter", () => {
115115
})
116116
expect(client._auth).toMatchObject({
117117
...auth,
118-
url: "/oauth/token",
119118
})
120119
})
121120
})

packages/next-drupal/tests/DrupalClient/fetch-related-methods.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,19 +278,19 @@ describe("getAccessToken()", () => {
278278
expect(fetchSpy).toHaveBeenCalledTimes(0)
279279
})
280280

281-
test("BUG: throws if auth is ClientIdSecret and not given as opts", async () => {
281+
test("throws if auth is not ClientIdSecret", async () => {
282282
const fetchSpy = spyOnFetch({
283283
responseBody: accessToken,
284284
})
285285

286286
const client = new DrupalClient(BASE_URL, {
287-
auth: clientIdSecret,
287+
auth: mocks.auth.basicAuth,
288288
withAuth: true,
289289
})
290290

291291
await expect(
292292
// @ts-ignore
293-
client.getAccessToken({ scope: "irrelevant" })
293+
client.getAccessToken()
294294
).rejects.toThrow(
295295
"'clientId' and 'clientSecret' required. See https://next-drupal.org/docs/client/auth"
296296
)

packages/next-drupal/tests/DrupalClient/getters-setters.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,12 @@ describe("auth", () => {
5757
})
5858

5959
describe("throws an error if invalid Access Token", () => {
60-
// TODO: The wrong error is thrown.
61-
test.skip("missing access_token", () => {
60+
test("missing access_token", () => {
6261
expect(() => {
6362
const client = new DrupalClient(BASE_URL)
6463
// @ts-ignore
6564
client.auth = {
66-
token_type: "bearer",
65+
token_type: mocks.auth.accessToken.token_type,
6766
}
6867
}).toThrow(
6968
"'access_token' and 'token_type' are required for auth. See https://next-drupal.org/docs/client/auth"
@@ -151,21 +150,21 @@ describe("auth", () => {
151150
})
152151

153152
test("sets a default access token url", () => {
154-
const accessToken = {
155-
...mocks.auth.accessToken,
153+
const clientIdSecret = {
154+
...mocks.auth.clientIdSecret,
156155
}
157156
const client = new DrupalClient(BASE_URL)
158-
client.auth = accessToken
157+
client.auth = clientIdSecret
159158
expect(client._auth.url).toBe("/oauth/token")
160159
})
161160

162161
test("can override the default access token url", () => {
163-
const accessToken = {
164-
...mocks.auth.accessToken,
162+
const clientIdSecret = {
163+
...mocks.auth.clientIdSecret,
165164
url: "/custom/oauth/token",
166165
}
167166
const client = new DrupalClient(BASE_URL)
168-
client.auth = accessToken
167+
client.auth = clientIdSecret
169168
expect(client._auth.url).toBe("/custom/oauth/token")
170169
})
171170
})

0 commit comments

Comments
 (0)