@osdk/oauth 0.0.0

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.
@@ -0,0 +1,198 @@
1
+ 'use strict';
2
+
3
+ var delay = require('delay');
4
+ var oauth4webapi = require('oauth4webapi');
5
+ var invariant = require('tiny-invariant');
6
+ var typescriptEventTarget = require('typescript-event-target');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var delay__default = /*#__PURE__*/_interopDefault(delay);
11
+ var invariant__default = /*#__PURE__*/_interopDefault(invariant);
12
+
13
+ // src/createPublicOauthClient.ts
14
+ function throwIfError(result) {
15
+ if (oauth4webapi.isOAuth2Error(result)) {
16
+ throw new Error(`Failed to get token: ${result.error}`);
17
+ }
18
+ return result;
19
+ }
20
+
21
+ // src/createPublicOauthClient.ts
22
+ var storageKey = "asdfasdfdhjlkajhgj";
23
+ function saveLocal(x) {
24
+ localStorage.setItem(storageKey, JSON.stringify(x));
25
+ }
26
+ function removeLocal() {
27
+ localStorage.removeItem(storageKey);
28
+ }
29
+ function readLocal() {
30
+ return JSON.parse(localStorage.getItem(storageKey) ?? "{}");
31
+ }
32
+ function createPublicOauthClient(client_id, url, redirectUrl, useHistory, loginPage, postLoginPage = window.location.toString(), scopes = ["api:read-data", "api:write-data"], fetchFn = globalThis.fetch, ctxPath = "/multipass") {
33
+ const oauthHttpOptions = {
34
+ [oauth4webapi.customFetch]: fetchFn
35
+ };
36
+ const eventTarget = new typescriptEventTarget.TypedEventTarget();
37
+ const issuer = `${new URL(ctxPath, url)}`;
38
+ const as = {
39
+ token_endpoint: `${issuer}/api/oauth2/token`,
40
+ authorization_endpoint: `${issuer}/api/oauth2/authorize`,
41
+ revocation_endpoint: `${issuer}/api/oauth2/revoke_token`,
42
+ issuer
43
+ };
44
+ const client = {
45
+ client_id,
46
+ token_endpoint_auth_method: "none"
47
+ };
48
+ async function go(x) {
49
+ if (useHistory)
50
+ return window.history.replaceState({}, "", x);
51
+ else
52
+ window.location.assign(x);
53
+ await delay__default.default(1e3);
54
+ throw new Error("Unable to redirect");
55
+ }
56
+ function makeTokenAndSaveRefresh(resp, type) {
57
+ const {
58
+ refresh_token,
59
+ expires_in,
60
+ access_token
61
+ } = resp;
62
+ !(expires_in != null) ? process.env.NODE_ENV !== "production" ? invariant__default.default(false) : invariant__default.default(false) : void 0;
63
+ saveLocal({
64
+ refresh_token
65
+ });
66
+ token = {
67
+ refresh_token,
68
+ expires_in,
69
+ access_token,
70
+ expires_at: Date.now() + expires_in * 1e3
71
+ };
72
+ eventTarget.dispatchTypedEvent(type, new CustomEvent(type, {
73
+ detail: token
74
+ }));
75
+ return token;
76
+ }
77
+ async function maybeRefresh(expectRefreshToken) {
78
+ const {
79
+ refresh_token
80
+ } = readLocal();
81
+ if (!refresh_token) {
82
+ if (expectRefreshToken)
83
+ throw new Error("No refresh token found");
84
+ return;
85
+ }
86
+ try {
87
+ return makeTokenAndSaveRefresh(throwIfError(await oauth4webapi.processAuthorizationCodeOAuth2Response(as, client, await oauth4webapi.refreshTokenGrantRequest(as, client, refresh_token, oauthHttpOptions))), "refresh");
88
+ } catch (e) {
89
+ if (!__DEV__) {
90
+ console.warn("Failed to get OAuth2 refresh token. Removing refresh token", e);
91
+ }
92
+ removeLocal();
93
+ if (expectRefreshToken) {
94
+ throw new Error("Could not refresh token");
95
+ }
96
+ }
97
+ }
98
+ async function maybeHandleAuthReturn() {
99
+ const {
100
+ codeVerifier,
101
+ state,
102
+ oldUrl
103
+ } = readLocal();
104
+ if (!codeVerifier)
105
+ return;
106
+ try {
107
+ const ret2 = makeTokenAndSaveRefresh(throwIfError(await oauth4webapi.processAuthorizationCodeOAuth2Response(as, client, await oauth4webapi.authorizationCodeGrantRequest(as, client, throwIfError(oauth4webapi.validateAuthResponse(as, client, new URL(window.location.href), state)), redirectUrl, codeVerifier, oauthHttpOptions))), "signIn");
108
+ go(oldUrl);
109
+ return ret2;
110
+ } catch (e) {
111
+ if (__DEV__) {
112
+ console.warn("Failed to get OAuth2 token using PCKE, removing PCKE and starting a new auth flow", e);
113
+ }
114
+ removeLocal();
115
+ }
116
+ }
117
+ async function initiateLoginRedirect() {
118
+ if (loginPage && window.location.href !== loginPage) {
119
+ saveLocal({
120
+ oldUrl: postLoginPage
121
+ });
122
+ return await go(loginPage);
123
+ }
124
+ const state = oauth4webapi.generateRandomState();
125
+ const codeVerifier = oauth4webapi.generateRandomCodeVerifier();
126
+ const oldUrl = readLocal().oldUrl ?? window.location.toString();
127
+ saveLocal({
128
+ codeVerifier,
129
+ state,
130
+ oldUrl
131
+ });
132
+ window.location.assign(`${as.authorization_endpoint}?${new URLSearchParams({
133
+ client_id,
134
+ response_type: "code",
135
+ state,
136
+ redirect_uri: redirectUrl,
137
+ code_challenge: await oauth4webapi.calculatePKCECodeChallenge(codeVerifier),
138
+ code_challenge_method: "S256",
139
+ scope: ["offline_access", ...scopes].join(" ")
140
+ })}`);
141
+ await delay__default.default(1e3);
142
+ throw new Error("Unable to redirect");
143
+ }
144
+ let refreshTimeout;
145
+ function rmTimeout() {
146
+ if (refreshTimeout)
147
+ clearTimeout(refreshTimeout);
148
+ }
149
+ function restartRefreshTimer(evt) {
150
+ rmTimeout();
151
+ refreshTimeout = setTimeout(refresh, evt.detail.expires_in * 1e3 - 60 * 1e3);
152
+ }
153
+ const refresh = maybeRefresh.bind(globalThis, true);
154
+ async function signOut() {
155
+ !token ? process.env.NODE_ENV !== "production" ? invariant__default.default(false, "not signed in") : invariant__default.default(false) : void 0;
156
+ const result = await oauth4webapi.processRevocationResponse(await oauth4webapi.revocationRequest(as, client, token.access_token, oauthHttpOptions));
157
+ rmTimeout();
158
+ removeLocal();
159
+ token = void 0;
160
+ throwIfError(result);
161
+ eventTarget.dispatchTypedEvent("signOut", new Event("signOut"));
162
+ }
163
+ let pendingSignIn;
164
+ async function signIn() {
165
+ if (pendingSignIn) {
166
+ return pendingSignIn;
167
+ }
168
+ try {
169
+ pendingSignIn = _signIn();
170
+ return await pendingSignIn;
171
+ } finally {
172
+ pendingSignIn = void 0;
173
+ }
174
+ }
175
+ async function _signIn() {
176
+ return token = await maybeRefresh() ?? await maybeHandleAuthReturn() ?? await initiateLoginRedirect();
177
+ }
178
+ eventTarget.addEventListener("signIn", restartRefreshTimer);
179
+ eventTarget.addEventListener("refresh", restartRefreshTimer);
180
+ let token;
181
+ const ret = Object.assign(async function ret2() {
182
+ if (!token || Date.now() >= token.expires_at) {
183
+ token = await signIn();
184
+ }
185
+ return token.access_token;
186
+ }, {
187
+ signIn,
188
+ refresh,
189
+ signOut,
190
+ addEventListener: eventTarget.addEventListener.bind(eventTarget),
191
+ removeEventListener: eventTarget.removeEventListener.bind(eventTarget)
192
+ });
193
+ return ret;
194
+ }
195
+
196
+ exports.createPublicOauthClient = createPublicOauthClient;
197
+ //# sourceMappingURL=out.js.map
198
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/createPublicOauthClient.ts","../../src/throwIfError.ts"],"names":["ret"],"mappings":"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","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 { authorizationCodeGrantRequest, calculatePKCECodeChallenge, customFetch, generateRandomCodeVerifier, generateRandomState, processAuthorizationCodeOAuth2Response, processRevocationResponse, refreshTokenGrantRequest, revocationRequest, validateAuthResponse } from \"oauth4webapi\";\nimport invariant from \"tiny-invariant\";\nimport { TypedEventTarget } from \"typescript-event-target\";\nimport { throwIfError } from \"./throwIfError.js\";\nconst storageKey = \"asdfasdfdhjlkajhgj\";\nfunction saveLocal(x) {\n localStorage.setItem(storageKey, JSON.stringify(x));\n}\nfunction removeLocal() {\n localStorage.removeItem(storageKey);\n}\nfunction readLocal() {\n return JSON.parse(localStorage.getItem(storageKey) ?? \"{}\");\n}\n\n/**\n * @param client_id\n * @param url the base url of your foundry server\n * @param redirectUrl the url configured for redirect in the oauth configuration on the server\n * @param useHistory if true, when possible uses `history.replaceState()`, otherwise uses `window.location.assign()`\n * @param loginPage if you want a custom landing page prior to logging in, set this to that url\n * @param postLoginPage if you want to customize where you return to after a completed authentication cycle. defaults to the url when the page loaded\n * @param scopes\n * @param fetchFn\n * @param ctxPath\n * @returns {PublicOauthClient} which can be used as a token provider\n */\nexport function createPublicOauthClient(client_id, url, redirectUrl, useHistory, loginPage, postLoginPage = window.location.toString(), scopes = [\"api:read-data\", \"api:write-data\"], fetchFn = globalThis.fetch, ctxPath = \"/multipass\") {\n const oauthHttpOptions = {\n [customFetch]: fetchFn\n };\n const eventTarget = new TypedEventTarget();\n const issuer = `${new URL(ctxPath, url)}`;\n const as = {\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 const client = {\n client_id,\n token_endpoint_auth_method: \"none\"\n };\n async function go(x) {\n if (useHistory) return window.history.replaceState({}, \"\", x);else window.location.assign(x);\n await delay(1000);\n throw new Error(\"Unable to redirect\");\n }\n function makeTokenAndSaveRefresh(resp, type) {\n const {\n refresh_token,\n expires_in,\n access_token\n } = resp;\n !(expires_in != null) ? process.env.NODE_ENV !== \"production\" ? invariant(false) : invariant(false) : void 0;\n saveLocal({\n refresh_token\n });\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, {\n detail: token\n }));\n return token;\n }\n async function maybeRefresh(expectRefreshToken) {\n const {\n refresh_token\n } = readLocal();\n if (!refresh_token) {\n if (expectRefreshToken) throw new Error(\"No refresh token found\");\n return;\n }\n try {\n // note, we dont use processRefreshTokenResponse because the mp oauth implementation\n // doesn't do refresh tokens quite right and this lets us skip the id check\n return makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(as, client, await refreshTokenGrantRequest(as, client, refresh_token, oauthHttpOptions))), \"refresh\");\n } catch (e) {\n if (!__DEV__) {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to get OAuth2 refresh token. Removing refresh token\", e);\n }\n removeLocal();\n if (expectRefreshToken) {\n throw new Error(\"Could not refresh token\");\n }\n }\n }\n async function maybeHandleAuthReturn() {\n const {\n codeVerifier,\n state,\n oldUrl\n } = readLocal();\n if (!codeVerifier) return;\n try {\n const ret = makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(as, client, await authorizationCodeGrantRequest(as, client, throwIfError(validateAuthResponse(as, client, new URL(window.location.href), state)), redirectUrl, codeVerifier, oauthHttpOptions))), \"signIn\");\n go(oldUrl);\n return ret;\n } catch (e) {\n if (__DEV__) {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to get OAuth2 token using PCKE, removing PCKE and starting a new auth flow\", e);\n }\n removeLocal();\n }\n }\n async function initiateLoginRedirect() {\n if (loginPage && window.location.href !== loginPage) {\n saveLocal({\n oldUrl: postLoginPage\n });\n return await go(loginPage);\n }\n const state = generateRandomState();\n const codeVerifier = generateRandomCodeVerifier();\n const oldUrl = readLocal().oldUrl ?? window.location.toString();\n saveLocal({\n codeVerifier,\n state,\n oldUrl\n });\n window.location.assign(`${as.authorization_endpoint}?${new URLSearchParams({\n client_id,\n response_type: \"code\",\n state,\n redirect_uri: redirectUrl,\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 let refreshTimeout;\n function rmTimeout() {\n if (refreshTimeout) clearTimeout(refreshTimeout);\n }\n function restartRefreshTimer(evt) {\n rmTimeout();\n refreshTimeout = setTimeout(refresh, evt.detail.expires_in * 1000 - 60 * 1000);\n }\n const refresh = maybeRefresh.bind(globalThis, true);\n async function signOut() {\n !token ? process.env.NODE_ENV !== \"production\" ? invariant(false, \"not signed in\") : invariant(false) : void 0;\n const result = await processRevocationResponse(await revocationRequest(as, client, token.access_token, oauthHttpOptions));\n rmTimeout();\n\n // Clean up\n removeLocal();\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 } finally {\n pendingSignIn = undefined;\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 token = (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 eventTarget.addEventListener(\"signIn\", restartRefreshTimer);\n eventTarget.addEventListener(\"refresh\", restartRefreshTimer);\n let token;\n const ret = Object.assign(async function ret() {\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 addEventListener: eventTarget.addEventListener.bind(eventTarget),\n removeEventListener: eventTarget.removeEventListener.bind(eventTarget)\n });\n return ret;\n}","/*\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 { isOAuth2Error } from \"oauth4webapi\";\nexport function throwIfError(result) {\n if (isOAuth2Error(result)) {\n throw new Error(`Failed to get token: ${result.error}`);\n }\n return result;\n}"]}
@@ -0,0 +1,191 @@
1
+ import delay from 'delay';
2
+ import { processAuthorizationCodeOAuth2Response, refreshTokenGrantRequest, processRevocationResponse, revocationRequest, isOAuth2Error, customFetch, authorizationCodeGrantRequest, validateAuthResponse, generateRandomState, generateRandomCodeVerifier, calculatePKCECodeChallenge } from 'oauth4webapi';
3
+ import invariant from 'tiny-invariant';
4
+ import { TypedEventTarget } from 'typescript-event-target';
5
+
6
+ // src/createPublicOauthClient.ts
7
+ function throwIfError(result) {
8
+ if (isOAuth2Error(result)) {
9
+ throw new Error(`Failed to get token: ${result.error}`);
10
+ }
11
+ return result;
12
+ }
13
+
14
+ // src/createPublicOauthClient.ts
15
+ var storageKey = "asdfasdfdhjlkajhgj";
16
+ function saveLocal(x) {
17
+ localStorage.setItem(storageKey, JSON.stringify(x));
18
+ }
19
+ function removeLocal() {
20
+ localStorage.removeItem(storageKey);
21
+ }
22
+ function readLocal() {
23
+ return JSON.parse(localStorage.getItem(storageKey) ?? "{}");
24
+ }
25
+ function createPublicOauthClient(client_id, url, redirectUrl, useHistory, loginPage, postLoginPage = window.location.toString(), scopes = ["api:read-data", "api:write-data"], fetchFn = globalThis.fetch, ctxPath = "/multipass") {
26
+ const oauthHttpOptions = {
27
+ [customFetch]: fetchFn
28
+ };
29
+ const eventTarget = new TypedEventTarget();
30
+ const issuer = `${new URL(ctxPath, url)}`;
31
+ const as = {
32
+ token_endpoint: `${issuer}/api/oauth2/token`,
33
+ authorization_endpoint: `${issuer}/api/oauth2/authorize`,
34
+ revocation_endpoint: `${issuer}/api/oauth2/revoke_token`,
35
+ issuer
36
+ };
37
+ const client = {
38
+ client_id,
39
+ token_endpoint_auth_method: "none"
40
+ };
41
+ async function go(x) {
42
+ if (useHistory)
43
+ return window.history.replaceState({}, "", x);
44
+ else
45
+ window.location.assign(x);
46
+ await delay(1e3);
47
+ throw new Error("Unable to redirect");
48
+ }
49
+ function makeTokenAndSaveRefresh(resp, type) {
50
+ const {
51
+ refresh_token,
52
+ expires_in,
53
+ access_token
54
+ } = resp;
55
+ !(expires_in != null) ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
56
+ saveLocal({
57
+ refresh_token
58
+ });
59
+ token = {
60
+ refresh_token,
61
+ expires_in,
62
+ access_token,
63
+ expires_at: Date.now() + expires_in * 1e3
64
+ };
65
+ eventTarget.dispatchTypedEvent(type, new CustomEvent(type, {
66
+ detail: token
67
+ }));
68
+ return token;
69
+ }
70
+ async function maybeRefresh(expectRefreshToken) {
71
+ const {
72
+ refresh_token
73
+ } = readLocal();
74
+ if (!refresh_token) {
75
+ if (expectRefreshToken)
76
+ throw new Error("No refresh token found");
77
+ return;
78
+ }
79
+ try {
80
+ return makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(as, client, await refreshTokenGrantRequest(as, client, refresh_token, oauthHttpOptions))), "refresh");
81
+ } catch (e) {
82
+ if (!__DEV__) {
83
+ console.warn("Failed to get OAuth2 refresh token. Removing refresh token", e);
84
+ }
85
+ removeLocal();
86
+ if (expectRefreshToken) {
87
+ throw new Error("Could not refresh token");
88
+ }
89
+ }
90
+ }
91
+ async function maybeHandleAuthReturn() {
92
+ const {
93
+ codeVerifier,
94
+ state,
95
+ oldUrl
96
+ } = readLocal();
97
+ if (!codeVerifier)
98
+ return;
99
+ try {
100
+ const ret2 = makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(as, client, await authorizationCodeGrantRequest(as, client, throwIfError(validateAuthResponse(as, client, new URL(window.location.href), state)), redirectUrl, codeVerifier, oauthHttpOptions))), "signIn");
101
+ go(oldUrl);
102
+ return ret2;
103
+ } catch (e) {
104
+ if (__DEV__) {
105
+ console.warn("Failed to get OAuth2 token using PCKE, removing PCKE and starting a new auth flow", e);
106
+ }
107
+ removeLocal();
108
+ }
109
+ }
110
+ async function initiateLoginRedirect() {
111
+ if (loginPage && window.location.href !== loginPage) {
112
+ saveLocal({
113
+ oldUrl: postLoginPage
114
+ });
115
+ return await go(loginPage);
116
+ }
117
+ const state = generateRandomState();
118
+ const codeVerifier = generateRandomCodeVerifier();
119
+ const oldUrl = readLocal().oldUrl ?? window.location.toString();
120
+ saveLocal({
121
+ codeVerifier,
122
+ state,
123
+ oldUrl
124
+ });
125
+ window.location.assign(`${as.authorization_endpoint}?${new URLSearchParams({
126
+ client_id,
127
+ response_type: "code",
128
+ state,
129
+ redirect_uri: redirectUrl,
130
+ code_challenge: await calculatePKCECodeChallenge(codeVerifier),
131
+ code_challenge_method: "S256",
132
+ scope: ["offline_access", ...scopes].join(" ")
133
+ })}`);
134
+ await delay(1e3);
135
+ throw new Error("Unable to redirect");
136
+ }
137
+ let refreshTimeout;
138
+ function rmTimeout() {
139
+ if (refreshTimeout)
140
+ clearTimeout(refreshTimeout);
141
+ }
142
+ function restartRefreshTimer(evt) {
143
+ rmTimeout();
144
+ refreshTimeout = setTimeout(refresh, evt.detail.expires_in * 1e3 - 60 * 1e3);
145
+ }
146
+ const refresh = maybeRefresh.bind(globalThis, true);
147
+ async function signOut() {
148
+ !token ? process.env.NODE_ENV !== "production" ? invariant(false, "not signed in") : invariant(false) : void 0;
149
+ const result = await processRevocationResponse(await revocationRequest(as, client, token.access_token, oauthHttpOptions));
150
+ rmTimeout();
151
+ removeLocal();
152
+ token = void 0;
153
+ throwIfError(result);
154
+ eventTarget.dispatchTypedEvent("signOut", new Event("signOut"));
155
+ }
156
+ let pendingSignIn;
157
+ async function signIn() {
158
+ if (pendingSignIn) {
159
+ return pendingSignIn;
160
+ }
161
+ try {
162
+ pendingSignIn = _signIn();
163
+ return await pendingSignIn;
164
+ } finally {
165
+ pendingSignIn = void 0;
166
+ }
167
+ }
168
+ async function _signIn() {
169
+ return token = await maybeRefresh() ?? await maybeHandleAuthReturn() ?? await initiateLoginRedirect();
170
+ }
171
+ eventTarget.addEventListener("signIn", restartRefreshTimer);
172
+ eventTarget.addEventListener("refresh", restartRefreshTimer);
173
+ let token;
174
+ const ret = Object.assign(async function ret2() {
175
+ if (!token || Date.now() >= token.expires_at) {
176
+ token = await signIn();
177
+ }
178
+ return token.access_token;
179
+ }, {
180
+ signIn,
181
+ refresh,
182
+ signOut,
183
+ addEventListener: eventTarget.addEventListener.bind(eventTarget),
184
+ removeEventListener: eventTarget.removeEventListener.bind(eventTarget)
185
+ });
186
+ return ret;
187
+ }
188
+
189
+ export { createPublicOauthClient };
190
+ //# sourceMappingURL=out.js.map
191
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/createPublicOauthClient.ts","../../src/throwIfError.ts"],"names":["ret"],"mappings":"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","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 { authorizationCodeGrantRequest, calculatePKCECodeChallenge, customFetch, generateRandomCodeVerifier, generateRandomState, processAuthorizationCodeOAuth2Response, processRevocationResponse, refreshTokenGrantRequest, revocationRequest, validateAuthResponse } from \"oauth4webapi\";\nimport invariant from \"tiny-invariant\";\nimport { TypedEventTarget } from \"typescript-event-target\";\nimport { throwIfError } from \"./throwIfError.js\";\nconst storageKey = \"asdfasdfdhjlkajhgj\";\nfunction saveLocal(x) {\n localStorage.setItem(storageKey, JSON.stringify(x));\n}\nfunction removeLocal() {\n localStorage.removeItem(storageKey);\n}\nfunction readLocal() {\n return JSON.parse(localStorage.getItem(storageKey) ?? \"{}\");\n}\n\n/**\n * @param client_id\n * @param url the base url of your foundry server\n * @param redirectUrl the url configured for redirect in the oauth configuration on the server\n * @param useHistory if true, when possible uses `history.replaceState()`, otherwise uses `window.location.assign()`\n * @param loginPage if you want a custom landing page prior to logging in, set this to that url\n * @param postLoginPage if you want to customize where you return to after a completed authentication cycle. defaults to the url when the page loaded\n * @param scopes\n * @param fetchFn\n * @param ctxPath\n * @returns {PublicOauthClient} which can be used as a token provider\n */\nexport function createPublicOauthClient(client_id, url, redirectUrl, useHistory, loginPage, postLoginPage = window.location.toString(), scopes = [\"api:read-data\", \"api:write-data\"], fetchFn = globalThis.fetch, ctxPath = \"/multipass\") {\n const oauthHttpOptions = {\n [customFetch]: fetchFn\n };\n const eventTarget = new TypedEventTarget();\n const issuer = `${new URL(ctxPath, url)}`;\n const as = {\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 const client = {\n client_id,\n token_endpoint_auth_method: \"none\"\n };\n async function go(x) {\n if (useHistory) return window.history.replaceState({}, \"\", x);else window.location.assign(x);\n await delay(1000);\n throw new Error(\"Unable to redirect\");\n }\n function makeTokenAndSaveRefresh(resp, type) {\n const {\n refresh_token,\n expires_in,\n access_token\n } = resp;\n !(expires_in != null) ? process.env.NODE_ENV !== \"production\" ? invariant(false) : invariant(false) : void 0;\n saveLocal({\n refresh_token\n });\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, {\n detail: token\n }));\n return token;\n }\n async function maybeRefresh(expectRefreshToken) {\n const {\n refresh_token\n } = readLocal();\n if (!refresh_token) {\n if (expectRefreshToken) throw new Error(\"No refresh token found\");\n return;\n }\n try {\n // note, we dont use processRefreshTokenResponse because the mp oauth implementation\n // doesn't do refresh tokens quite right and this lets us skip the id check\n return makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(as, client, await refreshTokenGrantRequest(as, client, refresh_token, oauthHttpOptions))), \"refresh\");\n } catch (e) {\n if (!__DEV__) {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to get OAuth2 refresh token. Removing refresh token\", e);\n }\n removeLocal();\n if (expectRefreshToken) {\n throw new Error(\"Could not refresh token\");\n }\n }\n }\n async function maybeHandleAuthReturn() {\n const {\n codeVerifier,\n state,\n oldUrl\n } = readLocal();\n if (!codeVerifier) return;\n try {\n const ret = makeTokenAndSaveRefresh(throwIfError(await processAuthorizationCodeOAuth2Response(as, client, await authorizationCodeGrantRequest(as, client, throwIfError(validateAuthResponse(as, client, new URL(window.location.href), state)), redirectUrl, codeVerifier, oauthHttpOptions))), \"signIn\");\n go(oldUrl);\n return ret;\n } catch (e) {\n if (__DEV__) {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to get OAuth2 token using PCKE, removing PCKE and starting a new auth flow\", e);\n }\n removeLocal();\n }\n }\n async function initiateLoginRedirect() {\n if (loginPage && window.location.href !== loginPage) {\n saveLocal({\n oldUrl: postLoginPage\n });\n return await go(loginPage);\n }\n const state = generateRandomState();\n const codeVerifier = generateRandomCodeVerifier();\n const oldUrl = readLocal().oldUrl ?? window.location.toString();\n saveLocal({\n codeVerifier,\n state,\n oldUrl\n });\n window.location.assign(`${as.authorization_endpoint}?${new URLSearchParams({\n client_id,\n response_type: \"code\",\n state,\n redirect_uri: redirectUrl,\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 let refreshTimeout;\n function rmTimeout() {\n if (refreshTimeout) clearTimeout(refreshTimeout);\n }\n function restartRefreshTimer(evt) {\n rmTimeout();\n refreshTimeout = setTimeout(refresh, evt.detail.expires_in * 1000 - 60 * 1000);\n }\n const refresh = maybeRefresh.bind(globalThis, true);\n async function signOut() {\n !token ? process.env.NODE_ENV !== \"production\" ? invariant(false, \"not signed in\") : invariant(false) : void 0;\n const result = await processRevocationResponse(await revocationRequest(as, client, token.access_token, oauthHttpOptions));\n rmTimeout();\n\n // Clean up\n removeLocal();\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 } finally {\n pendingSignIn = undefined;\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 token = (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 eventTarget.addEventListener(\"signIn\", restartRefreshTimer);\n eventTarget.addEventListener(\"refresh\", restartRefreshTimer);\n let token;\n const ret = Object.assign(async function ret() {\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 addEventListener: eventTarget.addEventListener.bind(eventTarget),\n removeEventListener: eventTarget.removeEventListener.bind(eventTarget)\n });\n return ret;\n}","/*\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 { isOAuth2Error } from \"oauth4webapi\";\nexport function throwIfError(result) {\n if (isOAuth2Error(result)) {\n throw new Error(`Failed to get token: ${result.error}`);\n }\n return result;\n}"]}
@@ -0,0 +1,15 @@
1
+ import type { Token } from "./Token.js";
2
+ export type Events = {
3
+ signIn: CustomEvent<Token>;
4
+ signOut: Event;
5
+ refresh: CustomEvent<Token>;
6
+ };
7
+ export interface PublicOauthClient {
8
+ (): Promise<string>;
9
+ signIn: () => Promise<Token>;
10
+ refresh: () => Promise<Token | undefined>;
11
+ signOut: () => Promise<void>;
12
+ addEventListener: <T extends keyof Events & string>(type: T, listener: ((evt: Events[T]) => void) | null, options?: boolean | AddEventListenerOptions) => void;
13
+ removeEventListener: <T extends keyof Events & string>(type: T, callback: ((evt: Events[T]) => void) | null, options?: EventListenerOptions | boolean) => void;
14
+ }
15
+ //# sourceMappingURL=PublicOauthClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PublicOauthClient.d.ts","sourceRoot":"","sources":["../../src/PublicOauthClient.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,MAAM,MAAM,GAAG;IACnB,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEpB,MAAM,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IAC1C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B,gBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EAChD,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,EAC3C,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,KACxC,IAAI,CAAC;IAEV,mBAAmB,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EACnD,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,EAC3C,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,KACrC,IAAI,CAAC;CACX"}
@@ -0,0 +1,7 @@
1
+ export interface Token {
2
+ readonly access_token: string;
3
+ readonly expires_in: number;
4
+ readonly refresh_token?: string;
5
+ readonly expires_at: number;
6
+ }
7
+ //# sourceMappingURL=Token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Token.d.ts","sourceRoot":"","sources":["../../src/Token.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B"}
@@ -0,0 +1,15 @@
1
+ import type { PublicOauthClient } from "./PublicOauthClient.js";
2
+ /**
3
+ * @param client_id
4
+ * @param url the base url of your foundry server
5
+ * @param redirectUrl the url configured for redirect in the oauth configuration on the server
6
+ * @param useHistory if true, when possible uses `history.replaceState()`, otherwise uses `window.location.assign()`
7
+ * @param loginPage if you want a custom landing page prior to logging in, set this to that url
8
+ * @param postLoginPage if you want to customize where you return to after a completed authentication cycle. defaults to the url when the page loaded
9
+ * @param scopes
10
+ * @param fetchFn
11
+ * @param ctxPath
12
+ * @returns {PublicOauthClient} which can be used as a token provider
13
+ */
14
+ export declare function createPublicOauthClient(client_id: string, url: string, redirectUrl: string, useHistory?: boolean, loginPage?: string, postLoginPage?: string, scopes?: string[], fetchFn?: typeof globalThis.fetch, ctxPath?: string): PublicOauthClient;
15
+ //# sourceMappingURL=createPublicOauthClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPublicOauthClient.d.ts","sourceRoot":"","sources":["../../src/createPublicOauthClient.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAU,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AA+CxE;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,OAAO,EACpB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,GAAE,MAAmC,EAClD,MAAM,GAAE,MAAM,EAAwC,EACtD,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,EACnD,OAAO,GAAE,MAAqB,GAC7B,iBAAiB,CA0OnB"}
@@ -0,0 +1,3 @@
1
+ export { createPublicOauthClient } from "./createPublicOauthClient.js";
2
+ export type { PublicOauthClient } from "./PublicOauthClient.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { OAuth2Error } from "oauth4webapi";
2
+ import { isOAuth2Error } from "oauth4webapi";
3
+ type IsErrorInputs = Parameters<typeof isOAuth2Error>[0];
4
+ export declare function throwIfError<T extends IsErrorInputs>(result: T | OAuth2Error): Exclude<T, OAuth2Error>;
5
+ export {};
6
+ //# sourceMappingURL=throwIfError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"throwIfError.d.ts","sourceRoot":"","sources":["../../src/throwIfError.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,wBAAgB,YAAY,CAAC,CAAC,SAAS,aAAa,EAClD,MAAM,EAAE,CAAC,GAAG,WAAW,GACtB,OAAO,CAAC,CAAC,EAAE,WAAW,CAAC,CAKzB"}
@@ -0,0 +1,5 @@
1
+ type: improvement
2
+ improvement:
3
+ description: Public Oauth Client for v2
4
+ links:
5
+ - https://github.com/palantir/osdk-ts/pull/156
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@osdk/oauth",
3
+ "version": "0.0.0",
4
+ "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/palantir/osdk-ts.git"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "types": "./build/types/index.d.ts",
12
+ "import": "./build/js/index.mjs",
13
+ "require": "./build/js/index.cjs"
14
+ },
15
+ "./*": {
16
+ "types": "./build/types/public/*.d.ts",
17
+ "import": "./build/js/public/*.mjs",
18
+ "require": "./build/js/public/*.cjs"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "delay": "^6.0.0",
23
+ "oauth4webapi": "^2.10.3",
24
+ "tiny-invariant": "^1.3.1",
25
+ "typescript-event-target": "^1.1.0"
26
+ },
27
+ "devDependencies": {
28
+ "jest-extended": "^4.0.2",
29
+ "ts-expect": "^1.3.0",
30
+ "type-fest": "^4.14.0",
31
+ "typescript": "^5.4.2"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "files": [
37
+ "build/types",
38
+ "build/js",
39
+ "changelog",
40
+ "CHANGELOG_OLD.md",
41
+ "package.json",
42
+ "templates",
43
+ "*.d.ts"
44
+ ],
45
+ "main": "./build/js/index.cjs",
46
+ "module": "./build/js/index.mjs",
47
+ "types": "./build/types/index.d.ts",
48
+ "type": "module",
49
+ "scripts": {
50
+ "clean": "rm -rf lib dist types build tsconfig.tsbuildinfo",
51
+ "fix-lint": "eslint . --fix && dprint fmt --config $(find-up dprint.json)",
52
+ "lint": "eslint . && dprint check --config $(find-up dprint.json)",
53
+ "transpile": "tsup",
54
+ "typecheck": "tsc-absolute"
55
+ }
56
+ }