@osdk/oauth 1.1.0-beta.7 → 1.1.0-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/build/browser/AuthorizationServer.test.js +1 -0
- package/build/browser/AuthorizationServer.test.js.map +1 -1
- package/build/browser/BaseOauthClient.js +0 -15
- package/build/browser/BaseOauthClient.js.map +1 -1
- package/build/browser/ConfidentialOauthClient.js +0 -15
- package/build/browser/ConfidentialOauthClient.js.map +1 -1
- package/build/browser/PublicOauthClient.js +0 -15
- package/build/browser/PublicOauthClient.js.map +1 -1
- package/build/browser/Token.js +0 -15
- package/build/browser/Token.js.map +1 -1
- package/build/browser/__tests__/createPublicOauthClient.test.js +3 -0
- package/build/browser/__tests__/createPublicOauthClient.test.js.map +1 -1
- package/build/browser/common.js +15 -9
- package/build/browser/common.js.map +1 -1
- package/build/browser/common.test.js +65 -0
- package/build/browser/common.test.js.map +1 -0
- package/build/browser/createConfidentialOauthClient.js +3 -1
- package/build/browser/createConfidentialOauthClient.js.map +1 -1
- package/build/browser/createPublicOauthClient.js +37 -4
- package/build/browser/createPublicOauthClient.js.map +1 -1
- package/build/browser/index.js +1 -0
- package/build/browser/index.js.map +1 -1
- package/build/browser/publicOauth.test.js +80 -21
- package/build/browser/publicOauth.test.js.map +1 -1
- package/build/browser/throwIfError.js +1 -0
- package/build/browser/throwIfError.js.map +1 -1
- package/build/browser/utils.js +4 -1
- package/build/browser/utils.js.map +1 -1
- package/build/cjs/index.cjs +320 -0
- package/build/cjs/index.cjs.map +1 -0
- package/build/{browser/createPublicOauthClient.d.ts → cjs/index.d.cts} +48 -5
- package/build/esm/AuthorizationServer.test.js +1 -0
- package/build/esm/AuthorizationServer.test.js.map +1 -1
- package/build/esm/BaseOauthClient.js +0 -15
- package/build/esm/BaseOauthClient.js.map +1 -1
- package/build/esm/ConfidentialOauthClient.js +0 -15
- package/build/esm/ConfidentialOauthClient.js.map +1 -1
- package/build/esm/PublicOauthClient.js +0 -15
- package/build/esm/PublicOauthClient.js.map +1 -1
- package/build/esm/Token.js +0 -15
- package/build/esm/Token.js.map +1 -1
- package/build/esm/__tests__/createPublicOauthClient.test.js +3 -0
- package/build/esm/__tests__/createPublicOauthClient.test.js.map +1 -1
- package/build/esm/common.js +15 -9
- package/build/esm/common.js.map +1 -1
- package/build/esm/common.test.js +65 -0
- package/build/esm/common.test.js.map +1 -0
- package/build/esm/createConfidentialOauthClient.js +3 -1
- package/build/esm/createConfidentialOauthClient.js.map +1 -1
- package/build/esm/createPublicOauthClient.js +37 -4
- package/build/esm/createPublicOauthClient.js.map +1 -1
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/esm/publicOauth.test.js +80 -21
- package/build/esm/publicOauth.test.js.map +1 -1
- package/build/esm/throwIfError.js +1 -0
- package/build/esm/throwIfError.js.map +1 -1
- package/build/esm/utils.js +4 -1
- package/build/esm/utils.js.map +1 -1
- package/build/types/AuthorizationServer.test.d.ts +1 -0
- package/build/types/BaseOauthClient.d.ts +14 -0
- package/build/{browser → types}/ConfidentialOauthClient.d.ts +1 -3
- package/build/{browser → types}/PublicOauthClient.d.ts +1 -2
- package/build/types/Token.d.ts +6 -0
- package/build/types/__tests__/createPublicOauthClient.test.d.ts +1 -0
- package/build/{browser → types}/common.d.ts +16 -18
- package/build/types/common.test.d.ts +1 -0
- package/build/{browser → types}/createConfidentialOauthClient.d.ts +8 -9
- package/build/types/createPublicOauthClient.d.ts +56 -0
- package/build/{browser → types}/index.d.ts +1 -2
- package/build/types/publicOauth.test.d.ts +1 -0
- package/build/{browser → types}/throwIfError.d.ts +0 -1
- package/build/{esm → types}/utils.d.ts +5 -4
- package/package.json +22 -8
- package/build/browser/AuthorizationServer.test.d.ts +0 -2
- package/build/browser/AuthorizationServer.test.d.ts.map +0 -1
- package/build/browser/BaseOauthClient.d.ts +0 -15
- package/build/browser/BaseOauthClient.d.ts.map +0 -1
- package/build/browser/ConfidentialOauthClient.d.ts.map +0 -1
- package/build/browser/PublicOauthClient.d.ts.map +0 -1
- package/build/browser/Token.d.ts +0 -7
- package/build/browser/Token.d.ts.map +0 -1
- package/build/browser/__tests__/createPublicOauthClient.test.d.ts +0 -2
- package/build/browser/__tests__/createPublicOauthClient.test.d.ts.map +0 -1
- package/build/browser/common.d.ts.map +0 -1
- package/build/browser/createConfidentialOauthClient.d.ts.map +0 -1
- package/build/browser/createPublicOauthClient.d.ts.map +0 -1
- package/build/browser/index.d.ts.map +0 -1
- package/build/browser/publicOauth.test.d.ts +0 -2
- package/build/browser/publicOauth.test.d.ts.map +0 -1
- package/build/browser/throwIfError.d.ts.map +0 -1
- package/build/browser/utils.d.ts +0 -6
- package/build/browser/utils.d.ts.map +0 -1
- package/build/esm/AuthorizationServer.test.d.ts +0 -2
- package/build/esm/AuthorizationServer.test.d.ts.map +0 -1
- package/build/esm/BaseOauthClient.d.ts +0 -15
- package/build/esm/BaseOauthClient.d.ts.map +0 -1
- package/build/esm/ConfidentialOauthClient.d.ts +0 -4
- package/build/esm/ConfidentialOauthClient.d.ts.map +0 -1
- package/build/esm/PublicOauthClient.d.ts +0 -6
- package/build/esm/PublicOauthClient.d.ts.map +0 -1
- package/build/esm/Token.d.ts +0 -7
- package/build/esm/Token.d.ts.map +0 -1
- package/build/esm/__tests__/createPublicOauthClient.test.d.ts +0 -2
- package/build/esm/__tests__/createPublicOauthClient.test.d.ts.map +0 -1
- package/build/esm/common.d.ts +0 -33
- package/build/esm/common.d.ts.map +0 -1
- package/build/esm/createConfidentialOauthClient.d.ts +0 -12
- package/build/esm/createConfidentialOauthClient.d.ts.map +0 -1
- package/build/esm/createPublicOauthClient.d.ts +0 -53
- package/build/esm/createPublicOauthClient.d.ts.map +0 -1
- package/build/esm/index.d.ts +0 -4
- package/build/esm/index.d.ts.map +0 -1
- package/build/esm/publicOauth.test.d.ts +0 -2
- package/build/esm/publicOauth.test.d.ts.map +0 -1
- package/build/esm/throwIfError.d.ts +0 -6
- package/build/esm/throwIfError.d.ts.map +0 -1
- package/build/esm/utils.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPublicOauthClient.test.js","names":["createPublicOauthClient","oauthModule","describe","expect","it","vi","utilsModule","originalCreatePublicOauthClient","FOUNDRY_CLIENT_ID","FOUNDRY_URL","REDIRECT_URI","stubGlobal","location","toString","fn","mockReturnValue","mockProcessOptionsAndAssignDefaults","spyOn","mockImplementation","args","processOptionsAndAssignDefaults","_client_id","rest","authClient","undefined","fetch","toBeDefined","toHaveBeenCalledTimes","authClientWithOptions","useHistory","fetchFn","result1","result2","mock","results","value","toEqual"],"sources":["createPublicOauthClient.test.
|
|
1
|
+
{"version":3,"file":"createPublicOauthClient.test.js","names":["createPublicOauthClient","oauthModule","describe","expect","it","vi","utilsModule","originalCreatePublicOauthClient","FOUNDRY_CLIENT_ID","FOUNDRY_URL","REDIRECT_URI","stubGlobal","location","toString","fn","mockReturnValue","mockProcessOptionsAndAssignDefaults","spyOn","mockImplementation","args","processOptionsAndAssignDefaults","_client_id","rest","authClient","undefined","fetch","toBeDefined","toHaveBeenCalledTimes","authClientWithOptions","useHistory","fetchFn","result1","result2","mock","results","value","toEqual"],"sources":["createPublicOauthClient.test.ts"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPublicOauthClient } from \"@osdk/oauth\";\nimport * as oauthModule from \"@osdk/oauth\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport * as utilsModule from \"../utils.js\";\n\nconst originalCreatePublicOauthClient = oauthModule.createPublicOauthClient;\n\nconst FOUNDRY_CLIENT_ID = \"example-foundry-client-id\";\nconst FOUNDRY_URL = \"http://example-foundry-url.com\";\nconst REDIRECT_URI = \"http://localhost:8080/auth/callback\";\n\nvi.stubGlobal(\"window\", {\n location: {\n toString: vi.fn().mockReturnValue(\"http://example.com\"),\n },\n});\n\ntype CreatePublicOauthClientParams = Parameters<typeof createPublicOauthClient>;\n\ntype ProcessedPublicOauthClientOptionsParams = Parameters<\n typeof utilsModule.processOptionsAndAssignDefaults\n>;\n\ntype ProcessedPublicOauthClientOptionsReturn = ReturnType<\n typeof utilsModule.processOptionsAndAssignDefaults\n>;\n\ndescribe(\"createPublicOauthClient\", () => {\n it(\"should return the same processed options for both client creation methods\", async () => {\n const mockProcessOptionsAndAssignDefaults = vi.fn<\n (\n ...args: ProcessedPublicOauthClientOptionsParams\n ) => ProcessedPublicOauthClientOptionsReturn\n >();\n\n // Mock processOptionsAndAssignDefaults to call the mock function\n vi.spyOn(utilsModule, \"processOptionsAndAssignDefaults\").mockImplementation(\n (\n ...args: ProcessedPublicOauthClientOptionsParams\n ) => {\n mockProcessOptionsAndAssignDefaults(...args);\n return utilsModule.processOptionsAndAssignDefaults(...args);\n },\n );\n\n // Mock createPublicOauthClient to call both the mock and the original function\n vi.spyOn(oauthModule, \"createPublicOauthClient\").mockImplementation(\n (\n ...args: CreatePublicOauthClientParams\n ) => {\n const [_client_id, ...rest] = args;\n mockProcessOptionsAndAssignDefaults(...rest);\n return originalCreatePublicOauthClient(...args);\n },\n );\n\n const authClient = createPublicOauthClient(\n FOUNDRY_CLIENT_ID,\n FOUNDRY_URL,\n REDIRECT_URI,\n true,\n undefined,\n undefined,\n undefined,\n fetch,\n undefined,\n );\n\n expect(authClient).toBeDefined();\n expect(mockProcessOptionsAndAssignDefaults).toHaveBeenCalledTimes(1);\n\n const authClientWithOptions = createPublicOauthClient(\n FOUNDRY_CLIENT_ID,\n FOUNDRY_URL,\n REDIRECT_URI,\n {\n useHistory: true,\n fetchFn: fetch,\n },\n );\n\n expect(authClientWithOptions).toBeDefined();\n expect(mockProcessOptionsAndAssignDefaults).toHaveBeenCalledTimes(2);\n\n const [result1, result2] = mockProcessOptionsAndAssignDefaults.mock.results;\n expect(result1.value).toEqual(result2.value);\n });\n});\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,uBAAuB,QAAQ,aAAa;AACrD,OAAO,KAAKC,WAAW,MAAM,aAAa;AAC1C,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,QAAQ;AACjD,OAAO,KAAKC,WAAW,MAAM,aAAa;AAE1C,MAAMC,+BAA+B,GAAGN,WAAW,CAACD,uBAAuB;AAE3E,MAAMQ,iBAAiB,GAAG,2BAA2B;AACrD,MAAMC,WAAW,GAAG,gCAAgC;AACpD,MAAMC,YAAY,GAAG,qCAAqC;AAE1DL,EAAE,CAACM,UAAU,CAAC,QAAQ,EAAE;EACtBC,QAAQ,EAAE;IACRC,QAAQ,EAAER,EAAE,CAACS,EAAE,CAAC,CAAC,CAACC,eAAe,CAAC,oBAAoB;EACxD;AACF,CAAC,CAAC;AAYFb,QAAQ,CAAC,yBAAyB,EAAE,MAAM;EACxCE,EAAE,CAAC,2EAA2E,EAAE,YAAY;IAC1F,MAAMY,mCAAmC,GAAGX,EAAE,CAACS,EAAE,CAI/C,CAAC;;IAEH;IACAT,EAAE,CAACY,KAAK,CAACX,WAAW,EAAE,iCAAiC,CAAC,CAACY,kBAAkB,CACzE,CACE,GAAGC,IAA6C,KAC7C;MACHH,mCAAmC,CAAC,GAAGG,IAAI,CAAC;MAC5C,OAAOb,WAAW,CAACc,+BAA+B,CAAC,GAAGD,IAAI,CAAC;IAC7D,CACF,CAAC;;IAED;IACAd,EAAE,CAACY,KAAK,CAAChB,WAAW,EAAE,yBAAyB,CAAC,CAACiB,kBAAkB,CACjE,CACE,GAAGC,IAAmC,KACnC;MACH,MAAM,CAACE,UAAU,EAAE,GAAGC,IAAI,CAAC,GAAGH,IAAI;MAClCH,mCAAmC,CAAC,GAAGM,IAAI,CAAC;MAC5C,OAAOf,+BAA+B,CAAC,GAAGY,IAAI,CAAC;IACjD,CACF,CAAC;IAED,MAAMI,UAAU,GAAGvB,uBAAuB,CACxCQ,iBAAiB,EACjBC,WAAW,EACXC,YAAY,EACZ,IAAI,EACJc,SAAS,EACTA,SAAS,EACTA,SAAS,EACTC,KAAK,EACLD,SACF,CAAC;IAEDrB,MAAM,CAACoB,UAAU,CAAC,CAACG,WAAW,CAAC,CAAC;IAChCvB,MAAM,CAACa,mCAAmC,CAAC,CAACW,qBAAqB,CAAC,CAAC,CAAC;IAEpE,MAAMC,qBAAqB,GAAG5B,uBAAuB,CACnDQ,iBAAiB,EACjBC,WAAW,EACXC,YAAY,EACZ;MACEmB,UAAU,EAAE,IAAI;MAChBC,OAAO,EAAEL;IACX,CACF,CAAC;IAEDtB,MAAM,CAACyB,qBAAqB,CAAC,CAACF,WAAW,CAAC,CAAC;IAC3CvB,MAAM,CAACa,mCAAmC,CAAC,CAACW,qBAAqB,CAAC,CAAC,CAAC;IAEpE,MAAM,CAACI,OAAO,EAAEC,OAAO,CAAC,GAAGhB,mCAAmC,CAACiB,IAAI,CAACC,OAAO;IAC3E/B,MAAM,CAAC4B,OAAO,CAACI,KAAK,CAAC,CAACC,OAAO,CAACJ,OAAO,CAACG,KAAK,CAAC;EAC9C,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
package/build/esm/common.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
|
|
16
17
|
import { processRevocationResponse, revocationRequest } from "oauth4webapi";
|
|
17
18
|
import invariant from "tiny-invariant";
|
|
18
19
|
import { TypedEventTarget } from "typescript-event-target";
|
|
@@ -29,33 +30,36 @@ const CustomEvent = globalThis.CustomEvent ?? class extends Event {
|
|
|
29
30
|
return this.#detail;
|
|
30
31
|
}
|
|
31
32
|
};
|
|
33
|
+
function localStorageKey(client) {
|
|
34
|
+
return `@osdk/oauth : refresh : ${client.client_id}`;
|
|
35
|
+
}
|
|
32
36
|
export function saveLocal(client, x) {
|
|
33
37
|
// MUST `localStorage?` as nodejs does not have localStorage
|
|
34
|
-
globalThis.localStorage?.setItem(
|
|
38
|
+
globalThis.localStorage?.setItem(localStorageKey(client), JSON.stringify(x));
|
|
35
39
|
}
|
|
36
40
|
export function removeLocal(client) {
|
|
37
41
|
// MUST `localStorage?` as nodejs does not have localStorage
|
|
38
|
-
globalThis.localStorage?.removeItem(
|
|
42
|
+
globalThis.localStorage?.removeItem(localStorageKey(client));
|
|
39
43
|
}
|
|
40
44
|
export function readLocal(client) {
|
|
41
45
|
return JSON.parse(
|
|
42
46
|
// MUST `localStorage?` as nodejs does not have localStorage
|
|
43
|
-
globalThis.localStorage?.getItem(
|
|
47
|
+
globalThis.localStorage?.getItem(localStorageKey(client)) ?? "{}");
|
|
44
48
|
}
|
|
45
49
|
export function saveSession(client, x) {
|
|
46
50
|
// MUST `sessionStorage?` as nodejs does not have sessionStorage
|
|
47
|
-
globalThis.sessionStorage?.setItem(
|
|
51
|
+
globalThis.sessionStorage?.setItem(localStorageKey(client), JSON.stringify(x));
|
|
48
52
|
}
|
|
49
53
|
export function removeSession(client) {
|
|
50
54
|
// MUST `sessionStorage?` as nodejs does not have sessionStorage
|
|
51
|
-
globalThis.sessionStorage?.removeItem(
|
|
55
|
+
globalThis.sessionStorage?.removeItem(localStorageKey(client));
|
|
52
56
|
}
|
|
53
57
|
export function readSession(client) {
|
|
54
58
|
return JSON.parse(
|
|
55
59
|
// MUST `sessionStorage?` as nodejs does not have sessionStorage
|
|
56
|
-
globalThis.sessionStorage?.getItem(
|
|
60
|
+
globalThis.sessionStorage?.getItem(localStorageKey(client)) ?? "{}");
|
|
57
61
|
}
|
|
58
|
-
export function common(client, as, _signIn, oauthHttpOptions, refresh) {
|
|
62
|
+
export function common(client, as, _signIn, oauthHttpOptions, refresh, refreshTokenMarker) {
|
|
59
63
|
let token;
|
|
60
64
|
const eventTarget = new TypedEventTarget();
|
|
61
65
|
function makeTokenAndSaveRefresh(resp, type) {
|
|
@@ -66,7 +70,8 @@ export function common(client, as, _signIn, oauthHttpOptions, refresh) {
|
|
|
66
70
|
} = resp;
|
|
67
71
|
!(expires_in != null) ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
|
|
68
72
|
saveLocal(client, {
|
|
69
|
-
refresh_token
|
|
73
|
+
refresh_token,
|
|
74
|
+
refreshTokenMarker
|
|
70
75
|
});
|
|
71
76
|
token = {
|
|
72
77
|
refresh_token,
|
|
@@ -121,6 +126,7 @@ export function common(client, as, _signIn, oauthHttpOptions, refresh) {
|
|
|
121
126
|
!token ? process.env.NODE_ENV !== "production" ? invariant(false, "not signed in") : invariant(false) : void 0;
|
|
122
127
|
const result = await processRevocationResponse(await revocationRequest(as, client, token.access_token, oauthHttpOptions));
|
|
123
128
|
rmTimeout();
|
|
129
|
+
|
|
124
130
|
// Clean up
|
|
125
131
|
removeLocal(client);
|
|
126
132
|
token = undefined;
|
|
@@ -138,7 +144,7 @@ export function common(client, as, _signIn, oauthHttpOptions, refresh) {
|
|
|
138
144
|
};
|
|
139
145
|
}
|
|
140
146
|
export function createAuthorizationServer(ctxPath, url) {
|
|
141
|
-
const issuer = `${new URL(ctxPath, url)}`;
|
|
147
|
+
const issuer = `${new URL(ctxPath, url + "/")}`;
|
|
142
148
|
return {
|
|
143
149
|
token_endpoint: `${issuer}/api/oauth2/token`,
|
|
144
150
|
authorization_endpoint: `${issuer}/api/oauth2/authorize`,
|
package/build/esm/common.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","names":["processRevocationResponse","revocationRequest","invariant","TypedEventTarget","throwIfError","CustomEvent","globalThis","Event","detail","constructor","type","options","saveLocal","client","x","localStorage","setItem","client_id","JSON","stringify","removeLocal","removeItem","readLocal","parse","getItem","saveSession","sessionStorage","removeSession","readSession","common","as","_signIn","oauthHttpOptions","refresh","token","eventTarget","makeTokenAndSaveRefresh","resp","refresh_token","expires_in","access_token","process","env","NODE_ENV","expires_at","Date","now","dispatchTypedEvent","refreshTimeout","rmTimeout","clearTimeout","restartRefreshTimer","evt","setTimeout","pendingSignIn","signIn","undefined","addEventListener","getTokenOrUndefined","getToken","Object","assign","signOut","result","bind","removeEventListener","createAuthorizationServer","ctxPath","url","issuer","URL","token_endpoint","authorization_endpoint","revocation_endpoint"],"sources":["common.js"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { processRevocationResponse, revocationRequest } from \"oauth4webapi\";\nimport invariant from \"tiny-invariant\";\nimport { TypedEventTarget } from \"typescript-event-target\";\nimport { throwIfError } from \"./throwIfError.js\";\n// Node 18 is supposed to have a `CustomEvent` but it is not exposed on `globalThis`\n// which creates a problem for making a single codebase for node and browser. This polyfill works around it\nconst CustomEvent = process.env.TARGET === \"browser\"\n ? globalThis.CustomEvent\n : globalThis.CustomEvent\n ?? class CustomEvent extends Event {\n #detail;\n constructor(type, options) {\n super(type, options);\n this.#detail = options?.detail ?? null;\n }\n get detail() {\n return this.#detail;\n }\n };\nexport function saveLocal(client, x) {\n // MUST `localStorage?` as nodejs does not have localStorage\n globalThis.localStorage?.setItem(`@osdk/oauth : refresh : ${client.client_id}`, JSON.stringify(x));\n}\nexport function removeLocal(client) {\n // MUST `localStorage?` as nodejs does not have localStorage\n globalThis.localStorage?.removeItem(`@osdk/oauth : refresh : ${client.client_id}`);\n}\nexport function readLocal(client) {\n return JSON.parse(\n // MUST `localStorage?` as nodejs does not have localStorage\n globalThis.localStorage?.getItem(`@osdk/oauth : refresh : ${client.client_id}`)\n ?? \"{}\");\n}\nexport function saveSession(client, x) {\n // MUST `sessionStorage?` as nodejs does not have sessionStorage\n globalThis.sessionStorage?.setItem(`@osdk/oauth : refresh : ${client.client_id}`, JSON.stringify(x));\n}\nexport function removeSession(client) {\n // MUST `sessionStorage?` as nodejs does not have sessionStorage\n globalThis.sessionStorage?.removeItem(`@osdk/oauth : refresh : ${client.client_id}`);\n}\nexport function readSession(client) {\n return JSON.parse(\n // MUST `sessionStorage?` as nodejs does not have sessionStorage\n globalThis.sessionStorage?.getItem(`@osdk/oauth : refresh : ${client.client_id}`)\n ?? \"{}\");\n}\nexport function common(client, as, _signIn, oauthHttpOptions, refresh) {\n let token;\n const eventTarget = new TypedEventTarget();\n function makeTokenAndSaveRefresh(resp, type) {\n const { refresh_token, expires_in, access_token } = resp;\n invariant(expires_in != null);\n saveLocal(client, { refresh_token });\n token = {\n refresh_token,\n expires_in,\n access_token,\n expires_at: Date.now() + expires_in * 1000,\n };\n eventTarget.dispatchTypedEvent(type, new CustomEvent(type, { detail: token }));\n return token;\n }\n let refreshTimeout;\n function rmTimeout() {\n if (refreshTimeout)\n clearTimeout(refreshTimeout);\n }\n function restartRefreshTimer(evt) {\n if (refresh) {\n rmTimeout();\n refreshTimeout = setTimeout(refresh, evt.detail.expires_in * 1000 - 60 * 1000);\n }\n }\n async function signOut() {\n invariant(token, \"not signed in\");\n const result = await processRevocationResponse(await revocationRequest(as, client, token.access_token, oauthHttpOptions));\n rmTimeout();\n // Clean up\n removeLocal(client);\n token = undefined;\n throwIfError(result);\n eventTarget.dispatchTypedEvent(\"signOut\", new Event(\"signOut\"));\n }\n let pendingSignIn;\n async function signIn() {\n if (pendingSignIn) {\n return pendingSignIn;\n }\n try {\n pendingSignIn = _signIn();\n return await pendingSignIn;\n }\n finally {\n pendingSignIn = undefined;\n }\n }\n eventTarget.addEventListener(\"signIn\", restartRefreshTimer);\n eventTarget.addEventListener(\"refresh\", restartRefreshTimer);\n function getTokenOrUndefined() {\n if (!token || Date.now() >= token.expires_at) {\n return undefined;\n }\n return token?.access_token;\n }\n const getToken = Object.assign(async function getToken() {\n if (!token || Date.now() >= token.expires_at) {\n token = await signIn();\n }\n return token?.access_token;\n }, {\n signIn,\n refresh,\n signOut,\n rmTimeout,\n getTokenOrUndefined,\n addEventListener: eventTarget.addEventListener.bind(eventTarget),\n removeEventListener: eventTarget.removeEventListener.bind(eventTarget),\n });\n return { getToken, makeTokenAndSaveRefresh };\n}\nexport function createAuthorizationServer(ctxPath, url) {\n const issuer = `${new URL(ctxPath, url)}`;\n return {\n token_endpoint: `${issuer}/api/oauth2/token`,\n authorization_endpoint: `${issuer}/api/oauth2/authorize`,\n revocation_endpoint: `${issuer}/api/oauth2/revoke_token`,\n issuer,\n };\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,yBAAyB,EAAEC,iBAAiB,QAAQ,cAAc;AAC3E,OAAOC,SAAS,MAAM,gBAAgB;AACtC,SAASC,gBAAgB,QAAQ,yBAAyB;AAC1D,SAASC,YAAY,QAAQ,mBAAmB;AAChD;AACA;AACA,MAAMC,WAAW,GAEXC,UAAU,CAACD,WAAW,IACjB,cAA0BE,KAAK,CAAC;EAC/B,CAACC,MAAM;EACPC,WAAWA,CAACC,IAAI,EAAEC,OAAO,EAAE;IACvB,KAAK,CAACD,IAAI,EAAEC,OAAO,CAAC;IACpB,IAAI,CAAC,CAACH,MAAM,GAAGG,OAAO,EAAEH,MAAM,IAAI,IAAI;EAC1C;EACA,IAAIA,MAAMA,CAAA,EAAG;IACT,OAAO,IAAI,CAAC,CAACA,MAAM;EACvB;AACJ,CAAC;AACT,OAAO,SAASI,SAASA,CAACC,MAAM,EAAEC,CAAC,EAAE;EACjC;EACAR,UAAU,CAACS,YAAY,EAAEC,OAAO,CAAC,2BAA2BH,MAAM,CAACI,SAAS,EAAE,EAAEC,IAAI,CAACC,SAAS,CAACL,CAAC,CAAC,CAAC;AACtG;AACA,OAAO,SAASM,WAAWA,CAACP,MAAM,EAAE;EAChC;EACAP,UAAU,CAACS,YAAY,EAAEM,UAAU,CAAC,2BAA2BR,MAAM,CAACI,SAAS,EAAE,CAAC;AACtF;AACA,OAAO,SAASK,SAASA,CAACT,MAAM,EAAE;EAC9B,OAAOK,IAAI,CAACK,KAAK;EACjB;EACAjB,UAAU,CAACS,YAAY,EAAES,OAAO,CAAC,2BAA2BX,MAAM,CAACI,SAAS,EAAE,CAAC,IACxE,IAAI,CAAC;AAChB;AACA,OAAO,SAASQ,WAAWA,CAACZ,MAAM,EAAEC,CAAC,EAAE;EACnC;EACAR,UAAU,CAACoB,cAAc,EAAEV,OAAO,CAAC,2BAA2BH,MAAM,CAACI,SAAS,EAAE,EAAEC,IAAI,CAACC,SAAS,CAACL,CAAC,CAAC,CAAC;AACxG;AACA,OAAO,SAASa,aAAaA,CAACd,MAAM,EAAE;EAClC;EACAP,UAAU,CAACoB,cAAc,EAAEL,UAAU,CAAC,2BAA2BR,MAAM,CAACI,SAAS,EAAE,CAAC;AACxF;AACA,OAAO,SAASW,WAAWA,CAACf,MAAM,EAAE;EAChC,OAAOK,IAAI,CAACK,KAAK;EACjB;EACAjB,UAAU,CAACoB,cAAc,EAAEF,OAAO,CAAC,2BAA2BX,MAAM,CAACI,SAAS,EAAE,CAAC,IAC1E,IAAI,CAAC;AAChB;AACA,OAAO,SAASY,MAAMA,CAAChB,MAAM,EAAEiB,EAAE,EAAEC,OAAO,EAAEC,gBAAgB,EAAEC,OAAO,EAAE;EACnE,IAAIC,KAAK;EACT,MAAMC,WAAW,GAAG,IAAIhC,gBAAgB,CAAC,CAAC;EAC1C,SAASiC,uBAAuBA,CAACC,IAAI,EAAE3B,IAAI,EAAE;IACzC,MAAM;MAAE4B,aAAa;MAAEC,UAAU;MAAEC;IAAa,CAAC,GAAGH,IAAI;IACxD,EAAUE,UAAU,IAAI,IAAI,IAAAE,OAAA,CAAAC,GAAA,CAAAC,QAAA,oBAA5BzC,SAAS,UAATA,SAAS;IACTU,SAAS,CAACC,MAAM,EAAE;MAAEyB;IAAc,CAAC,CAAC;IACpCJ,KAAK,GAAG;MACJI,aAAa;MACbC,UAAU;MACVC,YAAY;MACZI,UAAU,EAAEC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAGP,UAAU,GAAG;IAC1C,CAAC;IACDJ,WAAW,CAACY,kBAAkB,CAACrC,IAAI,EAAE,IAAIL,WAAW,CAACK,IAAI,EAAE;MAAEF,MAAM,EAAE0B;IAAM,CAAC,CAAC,CAAC;IAC9E,OAAOA,KAAK;EAChB;EACA,IAAIc,cAAc;EAClB,SAASC,SAASA,CAAA,EAAG;IACjB,IAAID,cAAc,EACdE,YAAY,CAACF,cAAc,CAAC;EACpC;EACA,SAASG,mBAAmBA,CAACC,GAAG,EAAE;IAC9B,IAAInB,OAAO,EAAE;MACTgB,SAAS,CAAC,CAAC;MACXD,cAAc,GAAGK,UAAU,CAACpB,OAAO,EAAEmB,GAAG,CAAC5C,MAAM,CAAC+B,UAAU,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC;IAClF;EACJ;EAWA,IAAIe,aAAa;EACjB,eAAeC,MAAMA,CAAA,EAAG;IACpB,IAAID,aAAa,EAAE;MACf,OAAOA,aAAa;IACxB;IACA,IAAI;MACAA,aAAa,GAAGvB,OAAO,CAAC,CAAC;MACzB,OAAO,MAAMuB,aAAa;IAC9B,CAAC,SACO;MACJA,aAAa,GAAGE,SAAS;IAC7B;EACJ;EACArB,WAAW,CAACsB,gBAAgB,CAAC,QAAQ,EAAEN,mBAAmB,CAAC;EAC3DhB,WAAW,CAACsB,gBAAgB,CAAC,SAAS,EAAEN,mBAAmB,CAAC;EAC5D,SAASO,mBAAmBA,CAAA,EAAG;IAC3B,IAAI,CAACxB,KAAK,IAAIW,IAAI,CAACC,GAAG,CAAC,CAAC,IAAIZ,KAAK,CAACU,UAAU,EAAE;MAC1C,OAAOY,SAAS;IACpB;IACA,OAAOtB,KAAK,EAAEM,YAAY;EAC9B;EACA,MAAMmB,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAAC,eAAeF,QAAQA,CAAA,EAAG;IACrD,IAAI,CAACzB,KAAK,IAAIW,IAAI,CAACC,GAAG,CAAC,CAAC,IAAIZ,KAAK,CAACU,UAAU,EAAE;MAC1CV,KAAK,GAAG,MAAMqB,MAAM,CAAC,CAAC;IAC1B;IACA,OAAOrB,KAAK,EAAEM,YAAY;EAC9B,CAAC,EAAE;IACCe,MAAM;IACNtB,OAAO;IACP6B,OAAO,EAvCX,eAAeA,OAAOA,CAAA,EAAG;MACrB,CAAU5B,KAAK,GAAAO,OAAA,CAAAC,GAAA,CAAAC,QAAA,oBAAfzC,SAAS,QAAQ,eAAe,IAAhCA,SAAS;MACT,MAAM6D,MAAM,GAAG,MAAM/D,yBAAyB,CAAC,MAAMC,iBAAiB,CAAC6B,EAAE,EAAEjB,MAAM,EAAEqB,KAAK,CAACM,YAAY,EAAER,gBAAgB,CAAC,CAAC;MACzHiB,SAAS,CAAC,CAAC;MACX;MACA7B,WAAW,CAACP,MAAM,CAAC;MACnBqB,KAAK,GAAGsB,SAAS;MACjBpD,YAAY,CAAC2D,MAAM,CAAC;MACpB5B,WAAW,CAACY,kBAAkB,CAAC,SAAS,EAAE,IAAIxC,KAAK,CAAC,SAAS,CAAC,CAAC;IACnE,CA8BW;IACP0C,SAAS;IACTS,mBAAmB;IACnBD,gBAAgB,EAAEtB,WAAW,CAACsB,gBAAgB,CAACO,IAAI,CAAC7B,WAAW,CAAC;IAChE8B,mBAAmB,EAAE9B,WAAW,CAAC8B,mBAAmB,CAACD,IAAI,CAAC7B,WAAW;EACzE,CAAC,CAAC;EACF,OAAO;IAAEwB,QAAQ;IAAEvB;EAAwB,CAAC;AAChD;AACA,OAAO,SAAS8B,yBAAyBA,CAACC,OAAO,EAAEC,GAAG,EAAE;EACpD,MAAMC,MAAM,GAAG,GAAG,IAAIC,GAAG,CAACH,OAAO,EAAEC,GAAG,CAAC,EAAE;EACzC,OAAO;IACHG,cAAc,EAAE,GAAGF,MAAM,mBAAmB;IAC5CG,sBAAsB,EAAE,GAAGH,MAAM,uBAAuB;IACxDI,mBAAmB,EAAE,GAAGJ,MAAM,0BAA0B;IACxDA;EACJ,CAAC;AACL","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"common.js","names":["processRevocationResponse","revocationRequest","invariant","TypedEventTarget","throwIfError","CustomEvent","globalThis","Event","detail","constructor","type","options","localStorageKey","client","client_id","saveLocal","x","localStorage","setItem","JSON","stringify","removeLocal","removeItem","readLocal","parse","getItem","saveSession","sessionStorage","removeSession","readSession","common","as","_signIn","oauthHttpOptions","refresh","refreshTokenMarker","token","eventTarget","makeTokenAndSaveRefresh","resp","refresh_token","expires_in","access_token","process","env","NODE_ENV","expires_at","Date","now","dispatchTypedEvent","refreshTimeout","rmTimeout","clearTimeout","restartRefreshTimer","evt","setTimeout","pendingSignIn","signIn","undefined","addEventListener","getTokenOrUndefined","getToken","Object","assign","signOut","result","bind","removeEventListener","createAuthorizationServer","ctxPath","url","issuer","URL","token_endpoint","authorization_endpoint","revocation_endpoint"],"sources":["common.ts"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AuthorizationServer,\n Client,\n HttpRequestOptions,\n OAuth2TokenEndpointResponse,\n} from \"oauth4webapi\";\nimport { processRevocationResponse, revocationRequest } from \"oauth4webapi\";\nimport invariant from \"tiny-invariant\";\nimport { TypedEventTarget } from \"typescript-event-target\";\nimport type { BaseOauthClient, Events } from \"./BaseOauthClient.js\";\nimport { throwIfError } from \"./throwIfError.js\";\nimport type { Token } from \"./Token.js\";\n\n// Node 18 is supposed to have a `CustomEvent` but it is not exposed on `globalThis`\n// which creates a problem for making a single codebase for node and browser. This polyfill works around it\nconst CustomEvent = process.env.TARGET === \"browser\"\n ? globalThis.CustomEvent\n : globalThis.CustomEvent\n ?? class CustomEvent<T> extends Event {\n #detail: T | null;\n\n constructor(type: string, options: EventInit & { detail: T }) {\n super(type, options);\n this.#detail = options?.detail ?? null;\n }\n\n get detail() {\n return this.#detail;\n }\n };\n\ndeclare const process: {\n env: Record<string, string | undefined>;\n};\n\nexport interface LocalStorageState {\n refresh_token?: string;\n refreshTokenMarker?: string;\n}\n\nexport type SessionStorageState =\n // when we are going to the login page\n | {\n codeVerifier?: never;\n state?: never;\n oldUrl: string;\n }\n // when we are redirecting to oauth login\n | {\n codeVerifier: string;\n state: string;\n oldUrl: string;\n }\n // when we have the refresh token\n | {\n codeVerifier?: never;\n state?: never;\n oldUrl?: never;\n };\n\nfunction localStorageKey(client: Client) {\n return `@osdk/oauth : refresh : ${client.client_id}`;\n}\n\nexport function saveLocal(client: Client, x: LocalStorageState): void {\n // MUST `localStorage?` as nodejs does not have localStorage\n globalThis.localStorage?.setItem(\n localStorageKey(client),\n JSON.stringify(x),\n );\n}\n\nexport function removeLocal(client: Client): void {\n // MUST `localStorage?` as nodejs does not have localStorage\n globalThis.localStorage?.removeItem(\n localStorageKey(client),\n );\n}\n\nexport function readLocal(client: Client): LocalStorageState {\n return JSON.parse(\n // MUST `localStorage?` as nodejs does not have localStorage\n globalThis.localStorage?.getItem(\n localStorageKey(client),\n )\n ?? \"{}\",\n );\n}\n\nexport function saveSession(client: Client, x: SessionStorageState): void {\n // MUST `sessionStorage?` as nodejs does not have sessionStorage\n globalThis.sessionStorage?.setItem(\n localStorageKey(client),\n JSON.stringify(x),\n );\n}\n\nexport function removeSession(client: Client): void {\n // MUST `sessionStorage?` as nodejs does not have sessionStorage\n globalThis.sessionStorage?.removeItem(\n localStorageKey(client),\n );\n}\n\nexport function readSession(client: Client): SessionStorageState {\n return JSON.parse(\n // MUST `sessionStorage?` as nodejs does not have sessionStorage\n globalThis.sessionStorage?.getItem(\n localStorageKey(client),\n )\n ?? \"{}\",\n );\n}\n\nexport function common<\n R extends undefined | (() => Promise<Token | undefined>),\n>(\n client: Client,\n as: AuthorizationServer,\n _signIn: () => Promise<Token>,\n oauthHttpOptions: HttpRequestOptions,\n refresh: R,\n refreshTokenMarker: string | undefined,\n): {\n getToken: BaseOauthClient<keyof Events & string> & { refresh: R };\n makeTokenAndSaveRefresh: (\n resp: OAuth2TokenEndpointResponse,\n type: \"signIn\" | \"refresh\",\n ) => Token;\n} {\n let token: Token | undefined;\n const eventTarget = new TypedEventTarget<Events>();\n\n function makeTokenAndSaveRefresh(\n resp: OAuth2TokenEndpointResponse,\n type: \"signIn\" | \"refresh\",\n ): Token {\n const { refresh_token, expires_in, access_token } = resp;\n invariant(expires_in != null);\n saveLocal(client, {\n refresh_token,\n refreshTokenMarker,\n });\n token = {\n refresh_token,\n expires_in,\n access_token,\n expires_at: Date.now() + expires_in * 1000,\n };\n\n eventTarget.dispatchTypedEvent(\n type,\n new CustomEvent(\n type,\n { detail: token },\n ),\n );\n return token;\n }\n\n let refreshTimeout: ReturnType<typeof setTimeout>;\n function rmTimeout() {\n if (refreshTimeout) clearTimeout(refreshTimeout);\n }\n function restartRefreshTimer(evt: CustomEvent<Token>) {\n if (refresh) {\n rmTimeout();\n refreshTimeout = setTimeout(\n refresh,\n evt.detail.expires_in * 1000 - 60 * 1000,\n );\n }\n }\n\n async function signOut() {\n invariant(token, \"not signed in\");\n\n const result = await processRevocationResponse(\n await revocationRequest(\n as,\n client,\n token.access_token,\n oauthHttpOptions,\n ),\n );\n\n rmTimeout();\n\n // Clean up\n removeLocal(client);\n token = undefined;\n throwIfError(result);\n eventTarget.dispatchTypedEvent(\"signOut\", new Event(\"signOut\"));\n }\n\n let pendingSignIn: Promise<Token> | undefined;\n async function signIn() {\n if (pendingSignIn) {\n return pendingSignIn;\n }\n try {\n pendingSignIn = _signIn();\n return await pendingSignIn;\n } finally {\n pendingSignIn = undefined;\n }\n }\n\n eventTarget.addEventListener(\"signIn\", restartRefreshTimer);\n eventTarget.addEventListener(\"refresh\", restartRefreshTimer);\n\n function getTokenOrUndefined() {\n if (!token || Date.now() >= token.expires_at) {\n return undefined;\n }\n return token?.access_token;\n }\n\n const getToken = Object.assign(async function getToken() {\n if (!token || Date.now() >= token.expires_at) {\n token = await signIn();\n }\n return token?.access_token;\n }, {\n signIn,\n refresh,\n signOut,\n rmTimeout,\n getTokenOrUndefined,\n addEventListener: eventTarget.addEventListener.bind(\n eventTarget,\n ) as typeof eventTarget.addEventListener,\n removeEventListener: eventTarget.removeEventListener.bind(\n eventTarget,\n ) as typeof eventTarget.removeEventListener,\n });\n\n return { getToken, makeTokenAndSaveRefresh };\n}\n\nexport function createAuthorizationServer(\n ctxPath: string,\n url: string,\n): Required<\n Pick<\n AuthorizationServer,\n | \"issuer\"\n | \"token_endpoint\"\n | \"authorization_endpoint\"\n | \"revocation_endpoint\"\n >\n> {\n const issuer = `${new URL(ctxPath, url + \"/\")}`;\n return {\n token_endpoint: `${issuer}/api/oauth2/token`,\n authorization_endpoint: `${issuer}/api/oauth2/authorize`,\n revocation_endpoint: `${issuer}/api/oauth2/revoke_token`,\n issuer,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
18
|
+
import { common, createAuthorizationServer, readLocal, removeLocal, saveLocal } from "./common.js";
|
|
19
|
+
describe("local functions", () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
vi.stubGlobal("localStorage", {
|
|
22
|
+
setItem: vi.fn(),
|
|
23
|
+
removeItem: vi.fn(),
|
|
24
|
+
getItem: vi.fn()
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.unstubAllGlobals();
|
|
29
|
+
});
|
|
30
|
+
it("should use the old style keys when there is no refresh token marker", () => {
|
|
31
|
+
const client = {
|
|
32
|
+
client_id: "hi_mom",
|
|
33
|
+
$refreshTokenMarker: undefined
|
|
34
|
+
};
|
|
35
|
+
const oldLocalStorageKey = `@osdk/oauth : refresh : ${client.client_id}`;
|
|
36
|
+
readLocal(client);
|
|
37
|
+
removeLocal(client);
|
|
38
|
+
saveLocal(client, {});
|
|
39
|
+
expect(vi.mocked(globalThis.localStorage.getItem)).toBeCalledWith(oldLocalStorageKey);
|
|
40
|
+
expect(vi.mocked(globalThis.localStorage.setItem)).toBeCalledWith(oldLocalStorageKey, expect.anything());
|
|
41
|
+
expect(vi.mocked(globalThis.localStorage.removeItem)).toBeCalledWith(oldLocalStorageKey);
|
|
42
|
+
});
|
|
43
|
+
it("should save the refreshTokenMaker if it exists", () => {
|
|
44
|
+
const client = {
|
|
45
|
+
client_id: "hi_mom"
|
|
46
|
+
};
|
|
47
|
+
const signIn = vi.fn();
|
|
48
|
+
const refresh = vi.fn();
|
|
49
|
+
const authServer = createAuthorizationServer("multipass", "https://stack.palantir.com");
|
|
50
|
+
const {
|
|
51
|
+
makeTokenAndSaveRefresh
|
|
52
|
+
} = common(client, authServer, signIn, {}, refresh, "marker marker");
|
|
53
|
+
makeTokenAndSaveRefresh({
|
|
54
|
+
refresh_token: "refresh",
|
|
55
|
+
access_token: "access",
|
|
56
|
+
token_type: "idk",
|
|
57
|
+
expires_in: 10_000
|
|
58
|
+
}, "signIn");
|
|
59
|
+
expect(globalThis.localStorage.setItem).toBeCalledWith(`@osdk/oauth : refresh : ${client.client_id}`, JSON.stringify({
|
|
60
|
+
refresh_token: "refresh",
|
|
61
|
+
refreshTokenMarker: "marker marker"
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=common.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.test.js","names":["afterEach","beforeEach","describe","expect","it","vi","common","createAuthorizationServer","readLocal","removeLocal","saveLocal","stubGlobal","setItem","fn","removeItem","getItem","unstubAllGlobals","client","client_id","$refreshTokenMarker","undefined","oldLocalStorageKey","mocked","globalThis","localStorage","toBeCalledWith","anything","signIn","refresh","authServer","makeTokenAndSaveRefresh","refresh_token","access_token","token_type","expires_in","JSON","stringify","refreshTokenMarker"],"sources":["common.test.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n common,\n createAuthorizationServer,\n readLocal,\n removeLocal,\n saveLocal,\n} from \"./common.js\";\n\ndescribe(\"local functions\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"localStorage\", {\n setItem: vi.fn(),\n removeItem: vi.fn(),\n getItem: vi.fn(),\n });\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n });\n\n it(\"should use the old style keys when there is no refresh token marker\", () => {\n const client = {\n client_id: \"hi_mom\",\n $refreshTokenMarker: undefined,\n };\n\n const oldLocalStorageKey = `@osdk/oauth : refresh : ${client.client_id}`;\n\n readLocal(client);\n removeLocal(client);\n saveLocal(client, {});\n\n expect(vi.mocked(globalThis.localStorage.getItem)).toBeCalledWith(\n oldLocalStorageKey,\n );\n\n expect(vi.mocked(globalThis.localStorage.setItem)).toBeCalledWith(\n oldLocalStorageKey,\n expect.anything(),\n );\n\n expect(vi.mocked(globalThis.localStorage.removeItem)).toBeCalledWith(\n oldLocalStorageKey,\n );\n });\n\n it(\"should save the refreshTokenMaker if it exists\", () => {\n const client = {\n client_id: \"hi_mom\",\n };\n\n const signIn = vi.fn();\n const refresh = vi.fn();\n\n const authServer = createAuthorizationServer(\n \"multipass\",\n \"https://stack.palantir.com\",\n );\n\n const { makeTokenAndSaveRefresh } = common(\n client,\n authServer,\n signIn,\n {},\n refresh,\n \"marker marker\",\n );\n\n makeTokenAndSaveRefresh({\n refresh_token: \"refresh\",\n access_token: \"access\",\n token_type: \"idk\",\n expires_in: 10_000,\n }, \"signIn\");\n\n expect(globalThis.localStorage.setItem).toBeCalledWith(\n `@osdk/oauth : refresh : ${client.client_id}`,\n JSON.stringify({\n refresh_token: \"refresh\",\n refreshTokenMarker: \"marker marker\",\n }),\n );\n });\n});\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,SAAS,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,QAAQ;AACxE,SACEC,MAAM,EACNC,yBAAyB,EACzBC,SAAS,EACTC,WAAW,EACXC,SAAS,QACJ,aAAa;AAEpBR,QAAQ,CAAC,iBAAiB,EAAE,MAAM;EAChCD,UAAU,CAAC,MAAM;IACfI,EAAE,CAACM,UAAU,CAAC,cAAc,EAAE;MAC5BC,OAAO,EAAEP,EAAE,CAACQ,EAAE,CAAC,CAAC;MAChBC,UAAU,EAAET,EAAE,CAACQ,EAAE,CAAC,CAAC;MACnBE,OAAO,EAAEV,EAAE,CAACQ,EAAE,CAAC;IACjB,CAAC,CAAC;EACJ,CAAC,CAAC;EAEFb,SAAS,CAAC,MAAM;IACdK,EAAE,CAACW,gBAAgB,CAAC,CAAC;EACvB,CAAC,CAAC;EAEFZ,EAAE,CAAC,qEAAqE,EAAE,MAAM;IAC9E,MAAMa,MAAM,GAAG;MACbC,SAAS,EAAE,QAAQ;MACnBC,mBAAmB,EAAEC;IACvB,CAAC;IAED,MAAMC,kBAAkB,GAAG,2BAA2BJ,MAAM,CAACC,SAAS,EAAE;IAExEV,SAAS,CAACS,MAAM,CAAC;IACjBR,WAAW,CAACQ,MAAM,CAAC;IACnBP,SAAS,CAACO,MAAM,EAAE,CAAC,CAAC,CAAC;IAErBd,MAAM,CAACE,EAAE,CAACiB,MAAM,CAACC,UAAU,CAACC,YAAY,CAACT,OAAO,CAAC,CAAC,CAACU,cAAc,CAC/DJ,kBACF,CAAC;IAEDlB,MAAM,CAACE,EAAE,CAACiB,MAAM,CAACC,UAAU,CAACC,YAAY,CAACZ,OAAO,CAAC,CAAC,CAACa,cAAc,CAC/DJ,kBAAkB,EAClBlB,MAAM,CAACuB,QAAQ,CAAC,CAClB,CAAC;IAEDvB,MAAM,CAACE,EAAE,CAACiB,MAAM,CAACC,UAAU,CAACC,YAAY,CAACV,UAAU,CAAC,CAAC,CAACW,cAAc,CAClEJ,kBACF,CAAC;EACH,CAAC,CAAC;EAEFjB,EAAE,CAAC,gDAAgD,EAAE,MAAM;IACzD,MAAMa,MAAM,GAAG;MACbC,SAAS,EAAE;IACb,CAAC;IAED,MAAMS,MAAM,GAAGtB,EAAE,CAACQ,EAAE,CAAC,CAAC;IACtB,MAAMe,OAAO,GAAGvB,EAAE,CAACQ,EAAE,CAAC,CAAC;IAEvB,MAAMgB,UAAU,GAAGtB,yBAAyB,CAC1C,WAAW,EACX,4BACF,CAAC;IAED,MAAM;MAAEuB;IAAwB,CAAC,GAAGxB,MAAM,CACxCW,MAAM,EACNY,UAAU,EACVF,MAAM,EACN,CAAC,CAAC,EACFC,OAAO,EACP,eACF,CAAC;IAEDE,uBAAuB,CAAC;MACtBC,aAAa,EAAE,SAAS;MACxBC,YAAY,EAAE,QAAQ;MACtBC,UAAU,EAAE,KAAK;MACjBC,UAAU,EAAE;IACd,CAAC,EAAE,QAAQ,CAAC;IAEZ/B,MAAM,CAACoB,UAAU,CAACC,YAAY,CAACZ,OAAO,CAAC,CAACa,cAAc,CACpD,2BAA2BR,MAAM,CAACC,SAAS,EAAE,EAC7CiB,IAAI,CAACC,SAAS,CAAC;MACbL,aAAa,EAAE,SAAS;MACxBM,kBAAkB,EAAE;IACtB,CAAC,CACH,CAAC;EACH,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
|
|
16
17
|
import { clientCredentialsGrantRequest, customFetch, processClientCredentialsResponse } from "oauth4webapi";
|
|
17
18
|
import { common, createAuthorizationServer } from "./common.js";
|
|
18
19
|
import { throwIfError } from "./throwIfError.js";
|
|
20
|
+
|
|
19
21
|
/**
|
|
20
22
|
* @param client_id
|
|
21
23
|
* @param client_secret
|
|
@@ -41,7 +43,7 @@ export function createConfidentialOauthClient(client_id, client_secret, url, sco
|
|
|
41
43
|
return makeTokenAndSaveRefresh(throwIfError(await processClientCredentialsResponse(authServer, client, await clientCredentialsGrantRequest(authServer, client, new URLSearchParams({
|
|
42
44
|
scope: scopes.join(" ")
|
|
43
45
|
}), oauthHttpOptions))), "signIn");
|
|
44
|
-
}, oauthHttpOptions, undefined);
|
|
46
|
+
}, oauthHttpOptions, undefined, undefined);
|
|
45
47
|
return getToken;
|
|
46
48
|
}
|
|
47
49
|
//# sourceMappingURL=createConfidentialOauthClient.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createConfidentialOauthClient.js","names":["clientCredentialsGrantRequest","customFetch","processClientCredentialsResponse","common","createAuthorizationServer","throwIfError","createConfidentialOauthClient","client_id","client_secret","url","scopes","fetchFn","globalThis","fetch","ctxPath","client","authServer","oauthHttpOptions","getToken","makeTokenAndSaveRefresh","URLSearchParams","scope","join","undefined"],"sources":["createConfidentialOauthClient.
|
|
1
|
+
{"version":3,"file":"createConfidentialOauthClient.js","names":["clientCredentialsGrantRequest","customFetch","processClientCredentialsResponse","common","createAuthorizationServer","throwIfError","createConfidentialOauthClient","client_id","client_secret","url","scopes","fetchFn","globalThis","fetch","ctxPath","client","authServer","oauthHttpOptions","getToken","makeTokenAndSaveRefresh","URLSearchParams","scope","join","undefined"],"sources":["createConfidentialOauthClient.ts"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Client, HttpRequestOptions } from \"oauth4webapi\";\nimport {\n clientCredentialsGrantRequest,\n customFetch,\n processClientCredentialsResponse,\n} from \"oauth4webapi\";\nimport { common, createAuthorizationServer } from \"./common.js\";\nimport type { ConfidentialOauthClient } from \"./ConfidentialOauthClient.js\";\nimport { throwIfError } from \"./throwIfError.js\";\n\n/**\n * @param client_id\n * @param client_secret\n * @param url the base url of your foundry server\n * @param scopes\n * @param fetchFn\n * @param ctxPath\n * @returns which can be used as a token provider\n */\nexport function createConfidentialOauthClient(\n client_id: string,\n client_secret: string,\n url: string,\n scopes: string[] = [\"api:read-data\", \"api:write-data\"],\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n ctxPath: string = \"multipass\",\n): ConfidentialOauthClient {\n const client: Client = { client_id, client_secret };\n const authServer = createAuthorizationServer(ctxPath, url);\n const oauthHttpOptions: HttpRequestOptions = { [customFetch]: fetchFn };\n\n const { getToken, makeTokenAndSaveRefresh } = common(\n client,\n authServer,\n _signIn,\n oauthHttpOptions,\n undefined,\n undefined,\n );\n\n async function _signIn() {\n return makeTokenAndSaveRefresh(\n throwIfError(\n await processClientCredentialsResponse(\n authServer,\n client,\n await clientCredentialsGrantRequest(\n authServer,\n client,\n new URLSearchParams({ scope: scopes.join(\" \") }),\n oauthHttpOptions,\n ),\n ),\n ),\n \"signIn\",\n );\n }\n\n return getToken;\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,SACEA,6BAA6B,EAC7BC,WAAW,EACXC,gCAAgC,QAC3B,cAAc;AACrB,SAASC,MAAM,EAAEC,yBAAyB,QAAQ,aAAa;AAE/D,SAASC,YAAY,QAAQ,mBAAmB;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,6BAA6BA,CAC3CC,SAAiB,EACjBC,aAAqB,EACrBC,GAAW,EACXC,MAAgB,GAAG,CAAC,eAAe,EAAE,gBAAgB,CAAC,EACtDC,OAAgC,GAAGC,UAAU,CAACC,KAAK,EACnDC,OAAe,GAAG,WAAW,EACJ;EACzB,MAAMC,MAAc,GAAG;IAAER,SAAS;IAAEC;EAAc,CAAC;EACnD,MAAMQ,UAAU,GAAGZ,yBAAyB,CAACU,OAAO,EAAEL,GAAG,CAAC;EAC1D,MAAMQ,gBAAoC,GAAG;IAAE,CAAChB,WAAW,GAAGU;EAAQ,CAAC;EAEvE,MAAM;IAAEO,QAAQ;IAAEC;EAAwB,CAAC,GAAGhB,MAAM,CAClDY,MAAM,EACNC,UAAU,EAOZ,kBAAyB;IACvB,OAAOG,uBAAuB,CAC5Bd,YAAY,CACV,MAAMH,gCAAgC,CACpCc,UAAU,EACVD,MAAM,EACN,MAAMf,6BAA6B,CACjCgB,UAAU,EACVD,MAAM,EACN,IAAIK,eAAe,CAAC;MAAEC,KAAK,EAAEX,MAAM,CAACY,IAAI,CAAC,GAAG;IAAE,CAAC,CAAC,EAChDL,gBACF,CACF,CACF,CAAC,EACD,QACF,CAAC;EACH,CAAC,EArBCA,gBAAgB,EAChBM,SAAS,EACTA,SACF,CAAC;EAoBD,OAAOL,QAAQ;AACjB","ignoreList":[]}
|
|
@@ -13,19 +13,48 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
|
|
16
17
|
import delay from "delay";
|
|
17
18
|
import { authorizationCodeGrantRequest, calculatePKCECodeChallenge, customFetch, generateRandomCodeVerifier, generateRandomState, processAuthorizationCodeOAuth2Response, refreshTokenGrantRequest, validateAuthResponse } from "oauth4webapi";
|
|
18
19
|
import { common, createAuthorizationServer, readLocal, readSession, removeLocal, removeSession, saveLocal, saveSession } from "./common.js";
|
|
19
20
|
import { throwIfError } from "./throwIfError.js";
|
|
20
21
|
import { processOptionsAndAssignDefaults } from "./utils.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates a PublicOauthClient for authentication.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} clientId - The client_id from the OAuth configuration on the server
|
|
27
|
+
* @param {string} url - The base URL of your Foundry server
|
|
28
|
+
* @param {string} redirectUrl - The URL configured for redirect in the OAuth configuration on the server
|
|
29
|
+
* @param {PublicOauthClientOptions} options - Additional options for the client
|
|
30
|
+
* @returns {PublicOauthClient} A client that can be used as a token provider
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Creates a PublicOauthClient for authentication.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} clientId - The client_id from the OAuth configuration on the server
|
|
37
|
+
* @param {string} url - The base URL of your Foundry server
|
|
38
|
+
* @param {string} redirectUrl - The URL configured for redirect in the OAuth configuration on the server
|
|
39
|
+
* @param {boolean} useHistory - If true, uses `history.replaceState()`, otherwise uses `window.location.assign()` (defaults to true)
|
|
40
|
+
* @param {string} loginPage - Custom landing page URL prior to logging in
|
|
41
|
+
* @param {string} postLoginPage - URL to return to after completed authentication cycle (defaults to `window.location.toString()`)
|
|
42
|
+
* @param {string[]} scopes - OAuth scopes to request. If not provided, defaults to `["api:read-data", "api:write-data"]`
|
|
43
|
+
* @param {typeof globalThis.fetch} fetchFn - Custom fetch function to use for requests (defaults to `globalThis.fetch`)
|
|
44
|
+
* @param {string} ctxPath - Context path for the authorization server (defaults to "multipass")
|
|
45
|
+
* @returns {PublicOauthClient} A client that can be used as a token provider
|
|
46
|
+
*/
|
|
47
|
+
|
|
21
48
|
export function createPublicOauthClient(client_id, url, redirect_uri, useHistory, loginPage, postLoginPage, scopes, fetchFn, ctxPath) {
|
|
49
|
+
let refreshTokenMarker;
|
|
22
50
|
({
|
|
23
51
|
useHistory,
|
|
24
52
|
loginPage,
|
|
25
53
|
postLoginPage,
|
|
26
54
|
scopes,
|
|
27
55
|
fetchFn,
|
|
28
|
-
ctxPath
|
|
56
|
+
ctxPath,
|
|
57
|
+
refreshTokenMarker
|
|
29
58
|
} = processOptionsAndAssignDefaults(url, redirect_uri, useHistory, loginPage, postLoginPage, scopes, fetchFn, ctxPath));
|
|
30
59
|
const client = {
|
|
31
60
|
client_id,
|
|
@@ -46,7 +75,8 @@ export function createPublicOauthClient(client_id, url, redirect_uri, useHistory
|
|
|
46
75
|
) ?? (await maybeHandleAuthReturn())
|
|
47
76
|
// 3. If we haven't been able to load the token from one of the two above ways, we need to make the initial auth request
|
|
48
77
|
?? (await initiateLoginRedirect());
|
|
49
|
-
}, oauthHttpOptions, maybeRefresh.bind(globalThis, true));
|
|
78
|
+
}, oauthHttpOptions, maybeRefresh.bind(globalThis, true), refreshTokenMarker);
|
|
79
|
+
|
|
50
80
|
// as an arrow function, `useHistory` is known to be a boolean
|
|
51
81
|
const go = async x => {
|
|
52
82
|
if (useHistory) {
|
|
@@ -58,9 +88,10 @@ export function createPublicOauthClient(client_id, url, redirect_uri, useHistory
|
|
|
58
88
|
};
|
|
59
89
|
async function maybeRefresh(expectRefreshToken) {
|
|
60
90
|
const {
|
|
61
|
-
refresh_token
|
|
91
|
+
refresh_token,
|
|
92
|
+
refreshTokenMarker: lastRefreshTokenMarker
|
|
62
93
|
} = readLocal(client);
|
|
63
|
-
if (!refresh_token) {
|
|
94
|
+
if (!refresh_token || lastRefreshTokenMarker !== refreshTokenMarker) {
|
|
64
95
|
if (expectRefreshToken) throw new Error("No refresh token found");
|
|
65
96
|
return;
|
|
66
97
|
}
|
|
@@ -108,6 +139,7 @@ export function createPublicOauthClient(client_id, url, redirect_uri, useHistory
|
|
|
108
139
|
throw e;
|
|
109
140
|
}
|
|
110
141
|
}
|
|
142
|
+
|
|
111
143
|
// As an arrow function, `scopes` and `postLoginPage` are known at compile time
|
|
112
144
|
const initiateLoginRedirect = async () => {
|
|
113
145
|
if (loginPage && window.location.href !== loginPage && window.location.pathname !== loginPage) {
|
|
@@ -136,6 +168,7 @@ export function createPublicOauthClient(client_id, url, redirect_uri, useHistory
|
|
|
136
168
|
code_challenge_method: "S256",
|
|
137
169
|
scope: ["offline_access", ...scopes].join(" ")
|
|
138
170
|
})}`);
|
|
171
|
+
|
|
139
172
|
// Give time for redirect to happen
|
|
140
173
|
await delay(1000);
|
|
141
174
|
throw new Error("Unable to redirect");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPublicOauthClient.js","names":["delay","authorizationCodeGrantRequest","calculatePKCECodeChallenge","customFetch","generateRandomCodeVerifier","generateRandomState","processAuthorizationCodeOAuth2Response","refreshTokenGrantRequest","validateAuthResponse","common","createAuthorizationServer","readLocal","readSession","removeLocal","removeSession","saveLocal","saveSession","throwIfError","processOptionsAndAssignDefaults","createPublicOauthClient","client_id","url","redirect_uri","useHistory","loginPage","postLoginPage","scopes","fetchFn","ctxPath","client","token_endpoint_auth_method","authServer","oauthHttpOptions","makeTokenAndSaveRefresh","getToken","_signIn","maybeRefresh","maybeHandleAuthReturn","initiateLoginRedirect","bind","globalThis","go","x","window","history","replaceState","location","assign","Error","expectRefreshToken","refresh_token","result","pathname","URL","oldUrl","e","process","env","NODE_ENV","console","warn","state","codeVerifier","ret","href","toString","authorization_endpoint","URLSearchParams","response_type","code_challenge","code_challenge_method","scope","join"],"sources":["createPublicOauthClient.js"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport delay from \"delay\";\nimport { authorizationCodeGrantRequest, calculatePKCECodeChallenge, customFetch, generateRandomCodeVerifier, generateRandomState, processAuthorizationCodeOAuth2Response, refreshTokenGrantRequest, validateAuthResponse, } from \"oauth4webapi\";\nimport { common, createAuthorizationServer, readLocal, readSession, removeLocal, removeSession, saveLocal, saveSession, } from \"./common.js\";\nimport { throwIfError } from \"./throwIfError.js\";\nimport { processOptionsAndAssignDefaults } from \"./utils.js\";\nexport function createPublicOauthClient(client_id, url, redirect_uri, useHistory, loginPage, postLoginPage, scopes, fetchFn, ctxPath) {\n ({\n useHistory,\n loginPage,\n postLoginPage,\n scopes,\n fetchFn,\n ctxPath,\n } = processOptionsAndAssignDefaults(url, redirect_uri, useHistory, loginPage, postLoginPage, scopes, fetchFn, ctxPath));\n const client = { client_id, token_endpoint_auth_method: \"none\" };\n const authServer = createAuthorizationServer(ctxPath, url);\n const oauthHttpOptions = { [customFetch]: fetchFn };\n const { makeTokenAndSaveRefresh, getToken } = common(client, authServer, _signIn, oauthHttpOptions, maybeRefresh.bind(globalThis, true));\n // as an arrow function, `useHistory` is known to be a boolean\n const go = async (x) => {\n if (useHistory) {\n window.history.replaceState({}, \"\", x);\n return;\n }\n else\n window.location.assign(x);\n await delay(1000);\n throw new Error(\"Unable to redirect\");\n };\n async function maybeRefresh(expectRefreshToken) {\n const { refresh_token } = readLocal(client);\n if (!refresh_token) {\n if (expectRefreshToken)\n throw new Error(\"No refresh token found\");\n return;\n }\n try {\n // note, we don't use processRefreshTokenResponse because the mp oauth implementation\n // doesn't do refresh tokens quite right and this lets us skip the id check\n const result = makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(authServer, client, await refreshTokenGrantRequest(authServer, client, refresh_token, oauthHttpOptions))), \"refresh\");\n if (result && window.location.pathname === new URL(redirect_uri).pathname) {\n const { oldUrl } = readSession(client);\n // don't block on the redirect\n void go(oldUrl ?? \"/\");\n }\n return result;\n }\n catch (e) {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to get OAuth2 refresh token. Removing refresh token\", e);\n }\n removeLocal(client);\n if (expectRefreshToken) {\n throw new Error(\"Could not refresh token\");\n }\n }\n }\n async function maybeHandleAuthReturn() {\n const { state, oldUrl, codeVerifier } = readSession(client);\n if (!codeVerifier)\n return;\n try {\n const ret = makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(authServer, client, await authorizationCodeGrantRequest(authServer, client, throwIfError(validateAuthResponse(authServer, client, new URL(window.location.href), state)), redirect_uri, codeVerifier, oauthHttpOptions))), \"signIn\");\n void go(oldUrl);\n return ret;\n }\n catch (e) {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to get OAuth2 token using PKCE, removing PKCE and starting a new auth flow\", e);\n }\n removeLocal(client);\n removeSession(client);\n throw e;\n }\n }\n // As an arrow function, `scopes` and `postLoginPage` are known at compile time\n const initiateLoginRedirect = async () => {\n if (loginPage\n && window.location.href !== loginPage\n && window.location.pathname !== loginPage) {\n saveLocal(client, {});\n saveSession(client, { oldUrl: postLoginPage });\n await go(loginPage);\n return;\n }\n const state = generateRandomState();\n const codeVerifier = generateRandomCodeVerifier();\n const oldUrl = readSession(client).oldUrl ?? window.location.toString();\n saveLocal(client, {});\n saveSession(client, { codeVerifier, state, oldUrl });\n window.location.assign(`${authServer\n .authorization_endpoint}?${new URLSearchParams({\n client_id,\n response_type: \"code\",\n state,\n redirect_uri,\n code_challenge: await calculatePKCECodeChallenge(codeVerifier),\n code_challenge_method: \"S256\",\n scope: [\"offline_access\", ...scopes].join(\" \"),\n })}`);\n // Give time for redirect to happen\n await delay(1000);\n throw new Error(\"Unable to redirect\");\n };\n /** Will throw if there is no token! */\n async function _signIn() {\n // 1. Check if we have a refresh token in local storage\n return await maybeRefresh()\n // 2. If there is no refresh token we are likely trying to perform the callback\n ?? await maybeHandleAuthReturn()\n // 3. If we haven't been able to load the token from one of the two above ways, we need to make the initial auth request\n ?? await initiateLoginRedirect();\n }\n return getToken;\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"createPublicOauthClient.js","names":["delay","authorizationCodeGrantRequest","calculatePKCECodeChallenge","customFetch","generateRandomCodeVerifier","generateRandomState","processAuthorizationCodeOAuth2Response","refreshTokenGrantRequest","validateAuthResponse","common","createAuthorizationServer","readLocal","readSession","removeLocal","removeSession","saveLocal","saveSession","throwIfError","processOptionsAndAssignDefaults","createPublicOauthClient","client_id","url","redirect_uri","useHistory","loginPage","postLoginPage","scopes","fetchFn","ctxPath","refreshTokenMarker","client","token_endpoint_auth_method","authServer","oauthHttpOptions","makeTokenAndSaveRefresh","getToken","_signIn","maybeRefresh","maybeHandleAuthReturn","initiateLoginRedirect","bind","globalThis","go","x","window","history","replaceState","location","assign","Error","expectRefreshToken","refresh_token","lastRefreshTokenMarker","result","pathname","URL","oldUrl","e","process","env","NODE_ENV","console","warn","state","codeVerifier","ret","href","toString","authorization_endpoint","URLSearchParams","response_type","code_challenge","code_challenge_method","scope","join"],"sources":["createPublicOauthClient.ts"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport delay from \"delay\";\nimport type { Client, HttpRequestOptions } from \"oauth4webapi\";\nimport {\n authorizationCodeGrantRequest,\n calculatePKCECodeChallenge,\n customFetch,\n generateRandomCodeVerifier,\n generateRandomState,\n processAuthorizationCodeOAuth2Response,\n refreshTokenGrantRequest,\n validateAuthResponse,\n} from \"oauth4webapi\";\nimport {\n common,\n createAuthorizationServer,\n readLocal,\n readSession,\n removeLocal,\n removeSession,\n saveLocal,\n saveSession,\n} from \"./common.js\";\nimport type { PublicOauthClient } from \"./PublicOauthClient.js\";\nimport { throwIfError } from \"./throwIfError.js\";\nimport type { Token } from \"./Token.js\";\nimport { processOptionsAndAssignDefaults } from \"./utils.js\";\n\ndeclare const process: {\n env: {\n NODE_ENV: \"production\" | \"development\";\n TARGET: \"browser\" | \"node\";\n };\n};\n\nexport interface PublicOauthClientOptions {\n /**\n * If true, uses `history.replaceState()`, otherwise uses `window.location.assign()` (defaults to true)\n */\n useHistory?: boolean;\n\n /**\n * Custom landing page URL prior to logging in\n */\n loginPage?: string;\n\n /**\n * URL to return to after completed authentication cycle (defaults to `window.location.toString()`)\n */\n postLoginPage?: string;\n\n /**\n * * @param {string[]} [scopes=[]] - OAuth scopes to request. If not provided, defaults to `[\"api:read-data\", \"api:write-data\"]`\n */\n scopes?: string[];\n\n /**\n * Custom fetch function to use for requests (defaults to `globalThis.fetch`)\n */\n fetchFn?: typeof globalThis.fetch;\n\n /**\n * Context path for the authorization server (defaults to \"multipass\")\n */\n ctxPath?: string;\n\n /**\n * Allows for an additional value to be appended to the local storage key for the refresh token.\n */\n refreshTokenMarker?: string;\n}\n\n/**\n * Creates a PublicOauthClient for authentication.\n *\n * @param {string} clientId - The client_id from the OAuth configuration on the server\n * @param {string} url - The base URL of your Foundry server\n * @param {string} redirectUrl - The URL configured for redirect in the OAuth configuration on the server\n * @param {PublicOauthClientOptions} options - Additional options for the client\n * @returns {PublicOauthClient} A client that can be used as a token provider\n */\nexport function createPublicOauthClient(\n clientId: string,\n url: string,\n redirectUrl: string,\n options?: PublicOauthClientOptions,\n): PublicOauthClient;\n\n/**\n * Creates a PublicOauthClient for authentication.\n *\n * @param {string} clientId - The client_id from the OAuth configuration on the server\n * @param {string} url - The base URL of your Foundry server\n * @param {string} redirectUrl - The URL configured for redirect in the OAuth configuration on the server\n * @param {boolean} useHistory - If true, uses `history.replaceState()`, otherwise uses `window.location.assign()` (defaults to true)\n * @param {string} loginPage - Custom landing page URL prior to logging in\n * @param {string} postLoginPage - URL to return to after completed authentication cycle (defaults to `window.location.toString()`)\n * @param {string[]} scopes - OAuth scopes to request. If not provided, defaults to `[\"api:read-data\", \"api:write-data\"]`\n * @param {typeof globalThis.fetch} fetchFn - Custom fetch function to use for requests (defaults to `globalThis.fetch`)\n * @param {string} ctxPath - Context path for the authorization server (defaults to \"multipass\")\n * @returns {PublicOauthClient} A client that can be used as a token provider\n */\nexport function createPublicOauthClient(\n client_id: string,\n url: string,\n redirectUrl: string,\n useHistory?: boolean,\n loginPage?: string,\n postLoginPage?: string,\n scopes?: string[],\n fetchFn?: typeof globalThis.fetch,\n ctxPath?: string,\n): PublicOauthClient;\nexport function createPublicOauthClient(\n client_id: string,\n url: string,\n redirect_uri: string,\n useHistory?: boolean | PublicOauthClientOptions,\n loginPage?: string,\n postLoginPage?: string,\n scopes?: string[],\n fetchFn?: typeof globalThis.fetch,\n ctxPath?: string,\n): PublicOauthClient {\n let refreshTokenMarker: string | undefined;\n ({\n useHistory,\n loginPage,\n postLoginPage,\n scopes,\n fetchFn,\n ctxPath,\n refreshTokenMarker,\n } = processOptionsAndAssignDefaults(\n url,\n redirect_uri,\n useHistory,\n loginPage,\n postLoginPage,\n scopes,\n fetchFn,\n ctxPath,\n ));\n\n const client: Client = {\n client_id,\n token_endpoint_auth_method: \"none\",\n };\n const authServer = createAuthorizationServer(ctxPath, url);\n const oauthHttpOptions: HttpRequestOptions = { [customFetch]: fetchFn };\n\n const { makeTokenAndSaveRefresh, getToken } = common(\n client,\n authServer,\n _signIn,\n oauthHttpOptions,\n maybeRefresh.bind(globalThis, true),\n refreshTokenMarker,\n );\n\n // as an arrow function, `useHistory` is known to be a boolean\n const go = async (x: string) => {\n if (useHistory) {\n window.history.replaceState({}, \"\", x);\n return;\n } else window.location.assign(x);\n\n await delay(1000);\n throw new Error(\"Unable to redirect\");\n };\n\n async function maybeRefresh(\n expectRefreshToken?: boolean,\n ): Promise<Token | undefined> {\n const { refresh_token, refreshTokenMarker: lastRefreshTokenMarker } =\n readLocal(client);\n\n if (!refresh_token || lastRefreshTokenMarker !== refreshTokenMarker) {\n if (expectRefreshToken) throw new Error(\"No refresh token found\");\n return;\n }\n\n try {\n // note, we don't use processRefreshTokenResponse because the mp oauth implementation\n // doesn't do refresh tokens quite right and this lets us skip the id check\n const result = makeTokenAndSaveRefresh(\n throwIfError(\n await processAuthorizationCodeOAuth2Response(\n authServer,\n client,\n await refreshTokenGrantRequest(\n authServer,\n client,\n refresh_token,\n oauthHttpOptions,\n ),\n ),\n ),\n \"refresh\",\n );\n\n if (\n result && window.location.pathname === new URL(redirect_uri).pathname\n ) {\n const { oldUrl } = readSession(client);\n // don't block on the redirect\n void go(oldUrl ?? \"/\");\n }\n return result;\n } catch (e) {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n \"Failed to get OAuth2 refresh token. Removing refresh token\",\n e,\n );\n }\n removeLocal(client);\n if (expectRefreshToken) {\n throw new Error(\"Could not refresh token\");\n }\n }\n }\n\n async function maybeHandleAuthReturn() {\n const { state, oldUrl, codeVerifier } = readSession(client);\n if (!codeVerifier) return;\n\n try {\n const ret = makeTokenAndSaveRefresh(\n throwIfError(\n await processAuthorizationCodeOAuth2Response(\n authServer,\n client,\n await authorizationCodeGrantRequest(\n authServer,\n client,\n throwIfError(\n validateAuthResponse(\n authServer,\n client,\n new URL(window.location.href),\n state,\n ),\n ),\n redirect_uri,\n codeVerifier,\n oauthHttpOptions,\n ),\n ),\n ),\n \"signIn\",\n );\n\n void go(oldUrl);\n return ret;\n } catch (e) {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n \"Failed to get OAuth2 token using PKCE, removing PKCE and starting a new auth flow\",\n e,\n );\n }\n removeLocal(client);\n removeSession(client);\n throw e;\n }\n }\n\n // As an arrow function, `scopes` and `postLoginPage` are known at compile time\n const initiateLoginRedirect = async (): Promise<void> => {\n if (\n loginPage\n && window.location.href !== loginPage\n && window.location.pathname !== loginPage\n ) {\n saveLocal(client, {});\n saveSession(client, { oldUrl: postLoginPage });\n await go(loginPage);\n return;\n }\n\n const state = generateRandomState()!;\n const codeVerifier = generateRandomCodeVerifier();\n const oldUrl = readSession(client).oldUrl ?? window.location.toString();\n saveLocal(client, {});\n saveSession(client, { codeVerifier, state, oldUrl });\n\n window.location.assign(`${authServer\n .authorization_endpoint!}?${new URLSearchParams({\n client_id,\n response_type: \"code\",\n state,\n redirect_uri,\n code_challenge: await calculatePKCECodeChallenge(codeVerifier),\n code_challenge_method: \"S256\",\n scope: [\"offline_access\", ...scopes].join(\" \"),\n })}`);\n\n // Give time for redirect to happen\n await delay(1000);\n throw new Error(\"Unable to redirect\");\n };\n\n /** Will throw if there is no token! */\n async function _signIn() {\n // 1. Check if we have a refresh token in local storage\n return await maybeRefresh()\n // 2. If there is no refresh token we are likely trying to perform the callback\n ?? await maybeHandleAuthReturn()\n // 3. If we haven't been able to load the token from one of the two above ways, we need to make the initial auth request\n ?? await initiateLoginRedirect() as unknown as Token;\n }\n\n return getToken;\n}\n"],"mappings":"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","ignoreList":[]}
|
package/build/esm/index.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
|
|
16
17
|
export { createConfidentialOauthClient } from "./createConfidentialOauthClient.js";
|
|
17
18
|
export { createPublicOauthClient } from "./createPublicOauthClient.js";
|
|
18
19
|
//# sourceMappingURL=index.js.map
|
package/build/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["createConfidentialOauthClient","createPublicOauthClient"],"sources":["index.
|
|
1
|
+
{"version":3,"file":"index.js","names":["createConfidentialOauthClient","createPublicOauthClient"],"sources":["index.ts"],"sourcesContent":["/*\n * Copyright 2024 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport { createConfidentialOauthClient } from \"./createConfidentialOauthClient.js\";\nexport { createPublicOauthClient } from \"./createPublicOauthClient.js\";\nexport type { PublicOauthClient } from \"./PublicOauthClient.js\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,6BAA6B,QAAQ,oCAAoC;AAClF,SAASC,uBAAuB,QAAQ,8BAA8B","ignoreList":[]}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
|
|
16
17
|
/* eslint-disable @typescript-eslint/consistent-type-imports */
|
|
17
18
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
18
19
|
import * as commonJs from "./common.js";
|
|
@@ -95,6 +96,81 @@ describe(createPublicOauthClient, () => {
|
|
|
95
96
|
fetchFn
|
|
96
97
|
};
|
|
97
98
|
const fullLoginUrl = new URL("/loginPage", DEFAULT_CUR_URL);
|
|
99
|
+
function setupWindowLocation(currentUrl) {
|
|
100
|
+
mockWindow.location.href = new URL(currentUrl).href;
|
|
101
|
+
mockWindow.location.pathname = new URL(currentUrl).pathname;
|
|
102
|
+
}
|
|
103
|
+
function setupLocalState(initialLocalState) {
|
|
104
|
+
vi.mocked(commonJs.readLocal).mockImplementation(() => initialLocalState);
|
|
105
|
+
}
|
|
106
|
+
let client;
|
|
107
|
+
let clientArgs;
|
|
108
|
+
function setupClient(clientArgs_) {
|
|
109
|
+
clientArgs = clientArgs_;
|
|
110
|
+
if (clientArgs.refreshTokenMarker) {
|
|
111
|
+
client = createPublicOauthClient(clientArgs.clientId, clientArgs.foundryUrl, clientArgs.redirectUrl, clientArgs);
|
|
112
|
+
} else {
|
|
113
|
+
client = createPublicOauthClient(clientArgs.clientId, clientArgs.foundryUrl, clientArgs.redirectUrl, clientArgs.useHistory, clientArgs.loginPage, clientArgs.postLoginPage, clientArgs.scopes, clientArgs.fetchFn, clientArgs.ctxPath);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
beforeEach(() => {
|
|
117
|
+
// prevents mistakes like forgetting to initialize the client with an
|
|
118
|
+
// old value around
|
|
119
|
+
client = undefined;
|
|
120
|
+
clientArgs = undefined;
|
|
121
|
+
});
|
|
122
|
+
async function expectRedirectToMultipass(tokenPromise) {
|
|
123
|
+
// we assume window.location.assign will take you away therefore we
|
|
124
|
+
// also have to expect in this scenario that the thrown error happens
|
|
125
|
+
await expect(tokenPromise).rejects.toThrowError(new Error("Unable to redirect"));
|
|
126
|
+
expect(mockWindow.location.assign).toHaveBeenCalledOnce();
|
|
127
|
+
const url = new URL(mockWindow.location.assign.mock.calls[0][0]);
|
|
128
|
+
expect(url.origin).toEqual(clientArgs.foundryUrl);
|
|
129
|
+
expect(url.pathname).toEqual("/multipass/api/oauth2/authorize");
|
|
130
|
+
expect(Object.fromEntries(url.searchParams.entries())).toEqual(expect.objectContaining({
|
|
131
|
+
client_id: clientArgs.clientId,
|
|
132
|
+
code_challenge: expect.any(String),
|
|
133
|
+
redirect_uri: clientArgs.redirectUrl,
|
|
134
|
+
response_type: "code",
|
|
135
|
+
code_challenge_method: "S256",
|
|
136
|
+
scope: "offline_access api:read-data api:write-data",
|
|
137
|
+
state: expect.any(String)
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
describe("refresh token marker", () => {
|
|
141
|
+
beforeEach(() => {
|
|
142
|
+
setupWindowLocation("https://foundry.local");
|
|
143
|
+
});
|
|
144
|
+
it("should not allow refresh if the refresh markers do not match", async () => {
|
|
145
|
+
setupLocalState({
|
|
146
|
+
refresh_token: "refreshToken",
|
|
147
|
+
refreshTokenMarker: "not-the-right-marker"
|
|
148
|
+
});
|
|
149
|
+
setupClient({
|
|
150
|
+
...BASE_CLIENT_ARGS,
|
|
151
|
+
refreshTokenMarker: "marker"
|
|
152
|
+
});
|
|
153
|
+
await expectRedirectToMultipass(client());
|
|
154
|
+
});
|
|
155
|
+
it("should try to refresh if refresh tokens do match", async () => {
|
|
156
|
+
setupLocalState({
|
|
157
|
+
refresh_token: "refreshToken",
|
|
158
|
+
refreshTokenMarker: "marker"
|
|
159
|
+
});
|
|
160
|
+
setupClient({
|
|
161
|
+
...BASE_CLIENT_ARGS,
|
|
162
|
+
refreshTokenMarker: "marker"
|
|
163
|
+
});
|
|
164
|
+
hoistedMocks.makeTokenAndSaveRefresh.mockImplementationOnce(() => ({
|
|
165
|
+
access_token: "some token",
|
|
166
|
+
expires_at: Date.now(),
|
|
167
|
+
expires_in: 10000
|
|
168
|
+
}));
|
|
169
|
+
const tokenPromise = client();
|
|
170
|
+
await expect(tokenPromise).resolves.toEqual("some token");
|
|
171
|
+
expect(hoistedMocks.makeTokenAndSaveRefresh).toBeCalledTimes(1);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
98
174
|
describe.each([{
|
|
99
175
|
name: "Basic Usage",
|
|
100
176
|
currentUrl: DEFAULT_CUR_URL,
|
|
@@ -149,17 +225,15 @@ describe(createPublicOauthClient, () => {
|
|
|
149
225
|
currentUrl,
|
|
150
226
|
should
|
|
151
227
|
}) => {
|
|
152
|
-
let client;
|
|
153
228
|
beforeEach(() => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
mockWindow.location.pathname = new URL(currentUrl).pathname;
|
|
229
|
+
setupClient(clientArgs);
|
|
230
|
+
setupWindowLocation(currentUrl.toString());
|
|
157
231
|
});
|
|
158
232
|
it("calls common with expected values", () => {
|
|
159
233
|
expect(vi.mocked(commonJs.common)).toHaveBeenCalledWith(expect.objectContaining({
|
|
160
234
|
client_id: clientArgs.clientId,
|
|
161
235
|
token_endpoint_auth_method: "none"
|
|
162
|
-
}), commonJs.createAuthorizationServer(clientArgs.ctxPath ?? "/multipass", clientArgs.foundryUrl), expect.any(Function), expect.anything(), expect.any(Function));
|
|
236
|
+
}), commonJs.createAuthorizationServer(clientArgs.ctxPath ?? "/multipass", clientArgs.foundryUrl), expect.any(Function), expect.anything(), expect.any(Function), undefined);
|
|
163
237
|
});
|
|
164
238
|
describe.each([{
|
|
165
239
|
localStorage: {
|
|
@@ -214,22 +288,7 @@ describe(createPublicOauthClient, () => {
|
|
|
214
288
|
expect(mockWindow.history.replaceState).toHaveBeenCalledWith({}, "", clientArgs.loginPage);
|
|
215
289
|
return;
|
|
216
290
|
}
|
|
217
|
-
|
|
218
|
-
// also have to expect in this scenario that the thrown error happens
|
|
219
|
-
await expect(tokenPromise).rejects.toThrowError(new Error("Unable to redirect"));
|
|
220
|
-
expect(mockWindow.location.assign).toHaveBeenCalledOnce();
|
|
221
|
-
const url = new URL(mockWindow.location.assign.mock.calls[0][0]);
|
|
222
|
-
expect(url.origin).toEqual(clientArgs.foundryUrl);
|
|
223
|
-
expect(url.pathname).toEqual("/multipass/api/oauth2/authorize");
|
|
224
|
-
expect(Object.fromEntries(url.searchParams.entries())).toEqual(expect.objectContaining({
|
|
225
|
-
client_id: clientArgs.clientId,
|
|
226
|
-
code_challenge: expect.any(String),
|
|
227
|
-
redirect_uri: clientArgs.redirectUrl,
|
|
228
|
-
response_type: "code",
|
|
229
|
-
code_challenge_method: "S256",
|
|
230
|
-
scope: "offline_access api:read-data api:write-data",
|
|
231
|
-
state: expect.any(String)
|
|
232
|
-
}));
|
|
291
|
+
await expectRedirectToMultipass(tokenPromise);
|
|
233
292
|
});
|
|
234
293
|
}
|
|
235
294
|
}
|