@turnkey/react-wallet-kit 1.11.0 → 1.11.1
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/dist/providers/client/Provider.d.ts.map +1 -1
- package/dist/providers/client/Provider.js +300 -303
- package/dist/providers/client/Provider.js.map +1 -1
- package/dist/providers/client/Provider.mjs +145 -156
- package/dist/providers/client/Provider.mjs.map +1 -1
- package/dist/utils/oauth/completion.d.ts +132 -0
- package/dist/utils/oauth/completion.d.ts.map +1 -0
- package/dist/utils/oauth/completion.js +136 -0
- package/dist/utils/oauth/completion.js.map +1 -0
- package/dist/utils/oauth/completion.mjs +176 -0
- package/dist/utils/oauth/completion.mjs.map +1 -0
- package/dist/utils/oauth/config.d.ts +34 -0
- package/dist/utils/oauth/config.d.ts.map +1 -0
- package/dist/utils/oauth/config.js +69 -0
- package/dist/utils/oauth/config.js.map +1 -0
- package/dist/utils/oauth/config.mjs +54 -0
- package/dist/utils/oauth/config.mjs.map +1 -0
- package/dist/utils/oauth/helpers.d.ts +13 -0
- package/dist/utils/oauth/helpers.d.ts.map +1 -0
- package/dist/utils/oauth/helpers.js +38 -0
- package/dist/utils/oauth/helpers.js.map +1 -0
- package/dist/utils/oauth/helpers.mjs +35 -0
- package/dist/utils/oauth/helpers.mjs.map +1 -0
- package/dist/utils/oauth/index.d.ts +7 -0
- package/dist/utils/oauth/index.d.ts.map +1 -0
- package/dist/utils/oauth/pkce.d.ts +14 -0
- package/dist/utils/oauth/pkce.d.ts.map +1 -0
- package/dist/utils/oauth/pkce.js +48 -0
- package/dist/utils/oauth/pkce.js.map +1 -0
- package/dist/utils/oauth/pkce.mjs +85 -0
- package/dist/utils/oauth/pkce.mjs.map +1 -0
- package/dist/utils/oauth/storage.d.ts +48 -0
- package/dist/utils/oauth/storage.d.ts.map +1 -0
- package/dist/utils/oauth/storage.js +87 -0
- package/dist/utils/oauth/storage.js.map +1 -0
- package/dist/utils/oauth/storage.mjs +78 -0
- package/dist/utils/oauth/storage.mjs.map +1 -0
- package/dist/utils/oauth/url.d.ts +92 -0
- package/dist/utils/oauth/url.d.ts.map +1 -0
- package/dist/utils/oauth/url.js +222 -0
- package/dist/utils/oauth/url.js.map +1 -0
- package/dist/utils/oauth/url.mjs +228 -0
- package/dist/utils/oauth/url.mjs.map +1 -0
- package/package.json +3 -3
- package/dist/utils/oauth.d.ts +0 -323
- package/dist/utils/oauth.d.ts.map +0 -1
- package/dist/utils/oauth.js +0 -613
- package/dist/utils/oauth.js.map +0 -1
- package/dist/utils/oauth.mjs +0 -670
- package/dist/utils/oauth.mjs.map +0 -1
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var sha2 = require('@noble/hashes/sha2');
|
|
6
6
|
var utils$1 = require('@noble/hashes/utils');
|
|
7
|
-
var
|
|
7
|
+
var storage = require('../../utils/oauth/storage.js');
|
|
8
|
+
require('../../utils/oauth/config.js');
|
|
9
|
+
var url = require('../../utils/oauth/url.js');
|
|
10
|
+
var completion = require('../../utils/oauth/completion.js');
|
|
11
|
+
var pkce = require('../../utils/oauth/pkce.js');
|
|
12
|
+
var helpers = require('../../utils/oauth/helpers.js');
|
|
8
13
|
var utils = require('../../utils/utils.js');
|
|
9
14
|
var timers = require('../../utils/timers.js');
|
|
10
15
|
var core = require('@turnkey/core');
|
|
@@ -33,7 +38,7 @@ var Verify = require('../../components/verify/Verify.js');
|
|
|
33
38
|
var OnRamp = require('../../components/onramp/OnRamp.js');
|
|
34
39
|
var Svg = require('../../components/design/Svg.js');
|
|
35
40
|
var SendTransaction = require('../../components/send-transaction/SendTransaction.js');
|
|
36
|
-
var helpers = require('../../components/send-transaction/helpers.js');
|
|
41
|
+
var helpers$1 = require('../../components/send-transaction/helpers.js');
|
|
37
42
|
|
|
38
43
|
/**
|
|
39
44
|
* Provides Turnkey client authentication, session management, wallet operations, and user profile management
|
|
@@ -89,275 +94,267 @@ const ClientProvider = ({
|
|
|
89
94
|
closeModal
|
|
90
95
|
} = Hook.useModal();
|
|
91
96
|
const completeRedirectOauth = async () => {
|
|
92
|
-
//
|
|
93
|
-
if
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* This is the key difference between redirect and popup flows:
|
|
100
|
-
* - Popup: No modal needed (the popup window itself is the UI)
|
|
101
|
-
* - Redirect: Optional modal to show loading/success states on return
|
|
102
|
-
*/
|
|
103
|
-
const withModalWrapper = async params => {
|
|
104
|
-
const {
|
|
105
|
-
provider,
|
|
106
|
-
isAddProvider,
|
|
107
|
-
metadata,
|
|
108
|
-
openModal,
|
|
109
|
-
action
|
|
110
|
-
} = params;
|
|
111
|
-
const providerDisplayName = oauth.capitalizeProviderName(provider);
|
|
112
|
-
const icon = oauth.getProviderIcon(provider);
|
|
113
|
-
if (openModal === "true") {
|
|
114
|
-
// Show modal UI for the completion
|
|
115
|
-
await new Promise((resolve, reject) => {
|
|
116
|
-
pushPage({
|
|
117
|
-
key: `${providerDisplayName} OAuth`,
|
|
118
|
-
content: jsxRuntime.jsx(Action.ActionPage, {
|
|
119
|
-
closeOnComplete: isAddProvider ? false : true,
|
|
120
|
-
title: isAddProvider ? `Adding ${providerDisplayName} provider...` : `Authenticating with ${providerDisplayName}...`,
|
|
121
|
-
action: async () => {
|
|
122
|
-
try {
|
|
123
|
-
await action();
|
|
124
|
-
if (isAddProvider && metadata) {
|
|
125
|
-
// Don't show success for auth. Not needed
|
|
126
|
-
pushPage({
|
|
127
|
-
key: "OAuth Provider Added",
|
|
128
|
-
content: jsxRuntime.jsx(Success.SuccessPage, {
|
|
129
|
-
text: `Successfully added ${providerDisplayName} OAuth provider!`,
|
|
130
|
-
duration: metadata.successPageDuration ?? 2000,
|
|
131
|
-
onComplete: () => {
|
|
132
|
-
closeModal();
|
|
133
|
-
}
|
|
134
|
-
}),
|
|
135
|
-
preventBack: true,
|
|
136
|
-
showTitle: false
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
resolve();
|
|
140
|
-
} catch (err) {
|
|
141
|
-
if (isAddProvider) {
|
|
142
|
-
oauth.clearOAuthAddProviderMetadata();
|
|
143
|
-
}
|
|
144
|
-
reject(err);
|
|
145
|
-
popPage();
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
icon: jsxRuntime.jsx(reactFontawesome.FontAwesomeIcon, {
|
|
149
|
-
icon: icon,
|
|
150
|
-
size: "3x"
|
|
151
|
-
})
|
|
152
|
-
}),
|
|
153
|
-
showTitle: false,
|
|
154
|
-
onClose: () => {
|
|
155
|
-
if (isAddProvider) {
|
|
156
|
-
oauth.clearOAuthAddProviderMetadata();
|
|
157
|
-
}
|
|
158
|
-
reject(new sdkTypes.TurnkeyError(isAddProvider ? `User canceled the ${providerDisplayName} add provider process.` : `User canceled the ${providerDisplayName} authentication process.`, sdkTypes.TurnkeyErrorCodes.USER_CANCELED));
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
} else {
|
|
163
|
-
// No modal - execute directly
|
|
164
|
-
try {
|
|
165
|
-
await action();
|
|
166
|
-
} catch (err) {
|
|
167
|
-
if (isAddProvider) {
|
|
168
|
-
oauth.clearOAuthAddProviderMetadata();
|
|
169
|
-
}
|
|
170
|
-
throw err;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
// Handle PKCE-based OAuth redirects (Facebook, Discord, X) with code in search parameters
|
|
175
|
-
if (window.location.search && window.location.search.includes("code=") && window.location.search.includes("state=")) {
|
|
176
|
-
// Parse the URL using our unified helper
|
|
177
|
-
const result = oauth.parseOAuthResponse(window.location.href);
|
|
178
|
-
if (!result || !result.authCode || !result.publicKey) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
if (result.flow !== "redirect") {
|
|
182
|
-
// To complete OAuth we need redirect flow
|
|
97
|
+
// Since we use localStorage (see storage.ts), we always clean up OAuth data
|
|
98
|
+
// when this runs — even if there are no OAuth params in the URL (e.g. the
|
|
99
|
+
// user canceled at the provider and came back manually)
|
|
100
|
+
try {
|
|
101
|
+
// Check for either hash or search parameters that could indicate an OAuth redirect
|
|
102
|
+
if (!window.location.hash && !window.location.search) {
|
|
103
|
+
// No OAuth redirect parameters found, nothing to do
|
|
183
104
|
return;
|
|
184
105
|
}
|
|
185
|
-
const {
|
|
186
|
-
authCode: code,
|
|
187
|
-
provider,
|
|
188
|
-
publicKey,
|
|
189
|
-
oauthIntent,
|
|
190
|
-
sessionKey,
|
|
191
|
-
nonce,
|
|
192
|
-
openModal
|
|
193
|
-
} = result;
|
|
194
|
-
const isAddProvider = oauthIntent === oauth.OAUTH_INTENT_ADD_PROVIDER;
|
|
195
|
-
const metadata = isAddProvider ? oauth.getOAuthAddProviderMetadata() : null;
|
|
196
106
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
107
|
+
* Wraps an OAuth completion action with optional modal UI.
|
|
108
|
+
* This is the key difference between redirect and popup flows:
|
|
109
|
+
* - Popup: No modal needed (the popup window itself is the UI)
|
|
110
|
+
* - Redirect: Optional modal to show loading/success states on return
|
|
200
111
|
*/
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
await oauth.handlePKCEFlow({
|
|
205
|
-
publicKey,
|
|
206
|
-
providerName,
|
|
207
|
-
sessionKey: sessionKey ?? undefined,
|
|
208
|
-
callbacks,
|
|
209
|
-
completeOauth,
|
|
210
|
-
onAddProvider:
|
|
211
|
-
// Only set onAddProvider if we are adding a provider and have metadata
|
|
212
|
-
isAddProvider && metadata ? async oidcToken => {
|
|
213
|
-
await addOauthProvider({
|
|
214
|
-
providerName: provider,
|
|
215
|
-
oidcToken,
|
|
216
|
-
organizationId: metadata.organizationId,
|
|
217
|
-
userId: metadata.userId,
|
|
218
|
-
...(metadata.stampWith && {
|
|
219
|
-
stampWith: metadata.stampWith
|
|
220
|
-
})
|
|
221
|
-
});
|
|
222
|
-
oauth.clearOAuthAddProviderMetadata();
|
|
223
|
-
} : undefined,
|
|
224
|
-
exchangeCodeForToken: exchangeCodeFn
|
|
225
|
-
});
|
|
226
|
-
} catch (err) {
|
|
227
|
-
if (callbacks?.onError) {
|
|
228
|
-
const providerDisplayName = oauth.capitalizeProviderName(providerName);
|
|
229
|
-
callbacks.onError(err instanceof sdkTypes.TurnkeyError ? err : new sdkTypes.TurnkeyError(`${providerDisplayName} authentication failed`, sdkTypes.TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR, err));
|
|
230
|
-
}
|
|
231
|
-
throw err;
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
await withModalWrapper({
|
|
235
|
-
provider: providerName,
|
|
112
|
+
const withModalWrapper = async params => {
|
|
113
|
+
const {
|
|
114
|
+
provider,
|
|
236
115
|
isAddProvider,
|
|
237
116
|
metadata,
|
|
238
117
|
openModal,
|
|
239
118
|
action
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
|
|
119
|
+
} = params;
|
|
120
|
+
const providerDisplayName = helpers.capitalizeProviderName(provider);
|
|
121
|
+
const icon = helpers.getProviderIcon(provider);
|
|
122
|
+
if (openModal === "true") {
|
|
123
|
+
// Show modal UI for the completion
|
|
124
|
+
await new Promise((resolve, reject) => {
|
|
125
|
+
pushPage({
|
|
126
|
+
key: `${providerDisplayName} OAuth`,
|
|
127
|
+
content: jsxRuntime.jsx(Action.ActionPage, {
|
|
128
|
+
closeOnComplete: isAddProvider ? false : true,
|
|
129
|
+
title: isAddProvider ? `Adding ${providerDisplayName} provider...` : `Authenticating with ${providerDisplayName}...`,
|
|
130
|
+
action: async () => {
|
|
131
|
+
try {
|
|
132
|
+
await action();
|
|
133
|
+
if (isAddProvider && metadata) {
|
|
134
|
+
// Don't show success for auth. Not needed
|
|
135
|
+
pushPage({
|
|
136
|
+
key: "OAuth Provider Added",
|
|
137
|
+
content: jsxRuntime.jsx(Success.SuccessPage, {
|
|
138
|
+
text: `Successfully added ${providerDisplayName} OAuth provider!`,
|
|
139
|
+
duration: metadata.successPageDuration ?? 2000,
|
|
140
|
+
onComplete: () => {
|
|
141
|
+
closeModal();
|
|
142
|
+
}
|
|
143
|
+
}),
|
|
144
|
+
preventBack: true,
|
|
145
|
+
showTitle: false
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
resolve();
|
|
149
|
+
} catch (err) {
|
|
150
|
+
reject(err);
|
|
151
|
+
popPage();
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
icon: jsxRuntime.jsx(reactFontawesome.FontAwesomeIcon, {
|
|
155
|
+
icon: icon,
|
|
156
|
+
size: "3x"
|
|
157
|
+
})
|
|
158
|
+
}),
|
|
159
|
+
showTitle: false,
|
|
160
|
+
onClose: () => {
|
|
161
|
+
reject(new sdkTypes.TurnkeyError(isAddProvider ? `User canceled the ${providerDisplayName} add provider process.` : `User canceled the ${providerDisplayName} authentication process.`, sdkTypes.TurnkeyErrorCodes.USER_CANCELED));
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
} else {
|
|
166
|
+
// No modal - execute directly
|
|
167
|
+
await action();
|
|
168
|
+
}
|
|
243
169
|
};
|
|
244
|
-
//
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
170
|
+
// Handle PKCE-based OAuth redirects (Facebook, Discord, X) with code in search parameters
|
|
171
|
+
if (window.location.search && window.location.search.includes("code=") && window.location.search.includes("state=")) {
|
|
172
|
+
// Parse the URL using our unified helper
|
|
173
|
+
const result = url.parseOAuthResponse(window.location.href);
|
|
174
|
+
if (!result || !result.authCode || !result.publicKey) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (result.flow !== "redirect") {
|
|
178
|
+
// To complete OAuth we need redirect flow
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const {
|
|
182
|
+
authCode: code,
|
|
183
|
+
provider,
|
|
184
|
+
publicKey,
|
|
185
|
+
oauthIntent,
|
|
186
|
+
sessionKey,
|
|
187
|
+
nonce,
|
|
188
|
+
openModal
|
|
189
|
+
} = result;
|
|
190
|
+
const isAddProvider = oauthIntent === storage.OAUTH_INTENT_ADD_PROVIDER;
|
|
191
|
+
const metadata = isAddProvider ? storage.getOAuthAddProviderMetadata() : null;
|
|
192
|
+
/**
|
|
193
|
+
* Helper to complete PKCE redirect flow with optional modal wrapper.
|
|
194
|
+
* Uses completePKCEFlow from oauth utils for the core logic.
|
|
195
|
+
* We put this in a separate function to avoid duplicating for each provider.
|
|
196
|
+
*/
|
|
197
|
+
const completePKCERedirect = async (providerName, exchangeCodeFn) => {
|
|
198
|
+
const action = async () => {
|
|
199
|
+
try {
|
|
200
|
+
await completion.completePKCEFlow({
|
|
201
|
+
publicKey,
|
|
202
|
+
providerName,
|
|
203
|
+
sessionKey: sessionKey ?? undefined,
|
|
204
|
+
callbacks,
|
|
205
|
+
completeOauth,
|
|
206
|
+
onAddProvider:
|
|
207
|
+
// Only set onAddProvider if we are adding a provider and have metadata
|
|
208
|
+
isAddProvider && metadata ? async oidcToken => {
|
|
209
|
+
await addOauthProvider({
|
|
210
|
+
providerName: provider,
|
|
211
|
+
oidcToken,
|
|
212
|
+
organizationId: metadata.organizationId,
|
|
213
|
+
userId: metadata.userId,
|
|
214
|
+
...(metadata.stampWith && {
|
|
215
|
+
stampWith: metadata.stampWith
|
|
216
|
+
})
|
|
217
|
+
});
|
|
218
|
+
} : undefined,
|
|
219
|
+
exchangeCodeForToken: exchangeCodeFn
|
|
220
|
+
});
|
|
221
|
+
} catch (err) {
|
|
222
|
+
if (callbacks?.onError) {
|
|
223
|
+
const providerDisplayName = helpers.capitalizeProviderName(providerName);
|
|
224
|
+
callbacks.onError(err instanceof sdkTypes.TurnkeyError ? err : new sdkTypes.TurnkeyError(`${providerDisplayName} authentication failed`, sdkTypes.TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR, err));
|
|
225
|
+
}
|
|
226
|
+
throw err;
|
|
255
227
|
}
|
|
256
|
-
|
|
228
|
+
};
|
|
229
|
+
await withModalWrapper({
|
|
230
|
+
provider: providerName,
|
|
231
|
+
isAddProvider,
|
|
232
|
+
metadata,
|
|
233
|
+
openModal,
|
|
234
|
+
action
|
|
257
235
|
});
|
|
236
|
+
// Clean up URL after successful completion
|
|
237
|
+
url.cleanupOAuthUrl();
|
|
238
|
+
};
|
|
239
|
+
// FACEBOOK
|
|
240
|
+
if (provider === sdkTypes.OAuthProviders.FACEBOOK) {
|
|
241
|
+
const clientId = masterConfig?.auth?.oauthConfig?.facebookClientId;
|
|
242
|
+
const redirectURI = masterConfig?.auth?.oauthConfig?.oauthRedirectUri;
|
|
243
|
+
const hasVerifier = storage.hasPKCEVerifier(sdkTypes.OAuthProviders.FACEBOOK);
|
|
244
|
+
if (clientId && redirectURI && hasVerifier) {
|
|
245
|
+
await completePKCERedirect(sdkTypes.OAuthProviders.FACEBOOK, async codeVerifier => {
|
|
246
|
+
const tokenResponse = await pkce.exchangeFacebookCodeForToken(clientId, redirectURI, code, codeVerifier);
|
|
247
|
+
const oidcToken = tokenResponse?.id_token;
|
|
248
|
+
if (!oidcToken) {
|
|
249
|
+
throw new sdkTypes.TurnkeyError("Missing OIDC token", sdkTypes.TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
|
|
250
|
+
}
|
|
251
|
+
return oidcToken;
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return;
|
|
258
255
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
256
|
+
// DISCORD
|
|
257
|
+
if (provider === sdkTypes.OAuthProviders.DISCORD) {
|
|
258
|
+
const clientId = masterConfig?.auth?.oauthConfig?.discordClientId;
|
|
259
|
+
const redirectURI = masterConfig?.auth?.oauthConfig?.oauthRedirectUri;
|
|
260
|
+
const hasVerifier = storage.hasPKCEVerifier(sdkTypes.OAuthProviders.DISCORD);
|
|
261
|
+
if (clientId && redirectURI && hasVerifier && nonce) {
|
|
262
|
+
await completePKCERedirect(sdkTypes.OAuthProviders.DISCORD, async codeVerifier => {
|
|
263
|
+
const resp = await client?.httpClient.proxyOAuth2Authenticate({
|
|
264
|
+
provider: "OAUTH2_PROVIDER_DISCORD",
|
|
265
|
+
authCode: code,
|
|
266
|
+
redirectUri: redirectURI,
|
|
267
|
+
codeVerifier,
|
|
268
|
+
clientId,
|
|
269
|
+
nonce
|
|
270
|
+
});
|
|
271
|
+
const oidcToken = resp?.oidcToken;
|
|
272
|
+
if (!oidcToken) {
|
|
273
|
+
throw new sdkTypes.TurnkeyError("Missing OIDC token", sdkTypes.TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
|
|
274
|
+
}
|
|
275
|
+
return oidcToken;
|
|
275
276
|
});
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
throw new sdkTypes.TurnkeyError("Missing OIDC token", sdkTypes.TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
|
|
279
|
-
}
|
|
280
|
-
return oidcToken;
|
|
281
|
-
});
|
|
277
|
+
}
|
|
278
|
+
return;
|
|
282
279
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
280
|
+
// X (Twitter)
|
|
281
|
+
if (provider === sdkTypes.OAuthProviders.X) {
|
|
282
|
+
const clientId = masterConfig?.auth?.oauthConfig?.xClientId;
|
|
283
|
+
const redirectURI = masterConfig?.auth?.oauthConfig?.oauthRedirectUri;
|
|
284
|
+
const hasVerifier = storage.hasPKCEVerifier(sdkTypes.OAuthProviders.X);
|
|
285
|
+
if (clientId && redirectURI && hasVerifier && nonce) {
|
|
286
|
+
await completePKCERedirect(sdkTypes.OAuthProviders.X, async codeVerifier => {
|
|
287
|
+
const resp = await client?.httpClient.proxyOAuth2Authenticate({
|
|
288
|
+
provider: "OAUTH2_PROVIDER_X",
|
|
289
|
+
authCode: code,
|
|
290
|
+
redirectUri: redirectURI,
|
|
291
|
+
codeVerifier,
|
|
292
|
+
clientId,
|
|
293
|
+
nonce
|
|
294
|
+
});
|
|
295
|
+
const oidcToken = resp?.oidcToken;
|
|
296
|
+
if (!oidcToken) {
|
|
297
|
+
throw new sdkTypes.TurnkeyError("Missing OIDC token", sdkTypes.TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
|
|
298
|
+
}
|
|
299
|
+
return oidcToken;
|
|
299
300
|
});
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
throw new sdkTypes.TurnkeyError("Missing OIDC token", sdkTypes.TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
|
|
303
|
-
}
|
|
304
|
-
return oidcToken;
|
|
305
|
-
});
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
306
303
|
}
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
// Handle Google/Apple redirects (uses hash with idToken - non-PKCE)
|
|
311
|
-
if (window.location.hash) {
|
|
312
|
-
// Parse the URL using our unified helper
|
|
313
|
-
const result = oauth.parseOAuthResponse(window.location.href);
|
|
314
|
-
if (!result || !result.idToken || result.flow !== "redirect" || !result.publicKey) {
|
|
315
|
-
// idToken and publicKey are required to complete OAuth. These are both in the hash for non-PKCE providers
|
|
316
|
-
return;
|
|
317
304
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
// Use completeOAuthFlow from utils for the core completion logic
|
|
330
|
-
const action = async () => {
|
|
331
|
-
await oauth.completeOAuthFlow({
|
|
332
|
-
provider: resolvedProvider,
|
|
305
|
+
// Handle Google/Apple redirects (uses hash with idToken - non-PKCE)
|
|
306
|
+
if (window.location.hash) {
|
|
307
|
+
// Parse the URL using our unified helper
|
|
308
|
+
const result = url.parseOAuthResponse(window.location.href);
|
|
309
|
+
if (!result || !result.idToken || result.flow !== "redirect" || !result.publicKey) {
|
|
310
|
+
// idToken and publicKey are required to complete OAuth. These are both in the hash for non-PKCE providers
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const {
|
|
314
|
+
idToken,
|
|
315
|
+
provider,
|
|
333
316
|
publicKey,
|
|
334
|
-
|
|
335
|
-
sessionKey
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
317
|
+
openModal,
|
|
318
|
+
sessionKey,
|
|
319
|
+
oauthIntent
|
|
320
|
+
} = result;
|
|
321
|
+
const isAddProvider = oauthIntent === storage.OAUTH_INTENT_ADD_PROVIDER;
|
|
322
|
+
const metadata = isAddProvider ? storage.getOAuthAddProviderMetadata() : null;
|
|
323
|
+
const resolvedProvider = provider || sdkTypes.OAuthProviders.GOOGLE;
|
|
324
|
+
// Use completeOAuthFlow from utils for the core completion logic
|
|
325
|
+
const action = async () => {
|
|
326
|
+
await completion.completeOAuthFlow({
|
|
327
|
+
provider: resolvedProvider,
|
|
328
|
+
publicKey,
|
|
329
|
+
oidcToken: idToken,
|
|
330
|
+
sessionKey: sessionKey ?? undefined,
|
|
331
|
+
callbacks,
|
|
332
|
+
completeOauth,
|
|
333
|
+
onAddProvider: isAddProvider && metadata ? async oidcToken => {
|
|
334
|
+
await addOauthProvider({
|
|
335
|
+
providerName: resolvedProvider,
|
|
336
|
+
oidcToken,
|
|
337
|
+
organizationId: metadata.organizationId,
|
|
338
|
+
userId: metadata.userId,
|
|
339
|
+
...(metadata.stampWith && {
|
|
340
|
+
stampWith: metadata.stampWith
|
|
341
|
+
})
|
|
342
|
+
});
|
|
343
|
+
} : undefined
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
await withModalWrapper({
|
|
347
|
+
provider: resolvedProvider,
|
|
348
|
+
isAddProvider,
|
|
349
|
+
metadata,
|
|
350
|
+
openModal: openModal ?? undefined,
|
|
351
|
+
action
|
|
350
352
|
});
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
openModal: openModal ?? undefined,
|
|
357
|
-
action
|
|
358
|
-
});
|
|
359
|
-
// Clean up the URL after processing
|
|
360
|
-
oauth.cleanupOAuthUrlPreserveSearch();
|
|
353
|
+
// Clean up the URL after processing
|
|
354
|
+
url.cleanupOAuthUrlPreserveSearch();
|
|
355
|
+
}
|
|
356
|
+
} finally {
|
|
357
|
+
storage.clearAllOAuthData();
|
|
361
358
|
}
|
|
362
359
|
};
|
|
363
360
|
const buildConfig = proxyAuthConfig => {
|
|
@@ -1800,10 +1797,10 @@ const ClientProvider = ({
|
|
|
1800
1797
|
const {
|
|
1801
1798
|
verifier,
|
|
1802
1799
|
codeChallenge
|
|
1803
|
-
} = await
|
|
1804
|
-
|
|
1800
|
+
} = await pkce.generateChallengePair();
|
|
1801
|
+
storage.storePKCEVerifier(provider, verifier);
|
|
1805
1802
|
// Build OAuth URL
|
|
1806
|
-
const authUrl =
|
|
1803
|
+
const authUrl = url.buildOAuthUrl({
|
|
1807
1804
|
provider,
|
|
1808
1805
|
clientId,
|
|
1809
1806
|
redirectUri,
|
|
@@ -1815,12 +1812,12 @@ const ClientProvider = ({
|
|
|
1815
1812
|
});
|
|
1816
1813
|
if (openInPage) {
|
|
1817
1814
|
// Remainder of logic will occur in completeRedirectOauth
|
|
1818
|
-
return
|
|
1815
|
+
return url.redirectToOAuthProvider(authUrl);
|
|
1819
1816
|
}
|
|
1820
1817
|
// Popup flow
|
|
1821
|
-
const authWindow =
|
|
1818
|
+
const authWindow = url.openOAuthPopup();
|
|
1822
1819
|
if (!authWindow) {
|
|
1823
|
-
throw new Error(`Failed to open ${
|
|
1820
|
+
throw new Error(`Failed to open ${helpers.capitalizeProviderName(provider)} login window.`);
|
|
1824
1821
|
}
|
|
1825
1822
|
authWindow.location.href = authUrl;
|
|
1826
1823
|
return new Promise((resolve, reject) => {
|
|
@@ -1831,13 +1828,13 @@ const ClientProvider = ({
|
|
|
1831
1828
|
reject(new Error("Authentication window was closed."));
|
|
1832
1829
|
return;
|
|
1833
1830
|
}
|
|
1834
|
-
const url = authWindow.location.href || "";
|
|
1835
|
-
if (url.startsWith(window.location.origin)) {
|
|
1836
|
-
const result =
|
|
1831
|
+
const url$1 = authWindow.location.href || "";
|
|
1832
|
+
if (url$1.startsWith(window.location.origin)) {
|
|
1833
|
+
const result = url.parseOAuthResponse(url$1, provider);
|
|
1837
1834
|
if (result) {
|
|
1838
1835
|
authWindow.close();
|
|
1839
1836
|
clearInterval(interval);
|
|
1840
|
-
|
|
1837
|
+
completion.completeOAuthPopup({
|
|
1841
1838
|
provider,
|
|
1842
1839
|
publicKey,
|
|
1843
1840
|
result,
|
|
@@ -1895,10 +1892,10 @@ const ClientProvider = ({
|
|
|
1895
1892
|
const {
|
|
1896
1893
|
verifier,
|
|
1897
1894
|
codeChallenge
|
|
1898
|
-
} = await
|
|
1899
|
-
|
|
1895
|
+
} = await pkce.generateChallengePair();
|
|
1896
|
+
storage.storePKCEVerifier(provider, verifier);
|
|
1900
1897
|
// Build OAuth URL
|
|
1901
|
-
const authUrl =
|
|
1898
|
+
const authUrl = url.buildOAuthUrl({
|
|
1902
1899
|
provider,
|
|
1903
1900
|
clientId,
|
|
1904
1901
|
redirectUri,
|
|
@@ -1910,12 +1907,12 @@ const ClientProvider = ({
|
|
|
1910
1907
|
});
|
|
1911
1908
|
if (openInPage) {
|
|
1912
1909
|
// Remainder of logic will occur in completeRedirectOauth
|
|
1913
|
-
return
|
|
1910
|
+
return url.redirectToOAuthProvider(authUrl);
|
|
1914
1911
|
}
|
|
1915
1912
|
// Popup flow
|
|
1916
|
-
const authWindow =
|
|
1913
|
+
const authWindow = url.openOAuthPopup();
|
|
1917
1914
|
if (!authWindow) {
|
|
1918
|
-
throw new Error(`Failed to open ${
|
|
1915
|
+
throw new Error(`Failed to open ${helpers.capitalizeProviderName(provider)} login window.`);
|
|
1919
1916
|
}
|
|
1920
1917
|
authWindow.location.href = authUrl;
|
|
1921
1918
|
return new Promise((resolve, reject) => {
|
|
@@ -1926,13 +1923,13 @@ const ClientProvider = ({
|
|
|
1926
1923
|
reject(new Error("Authentication window was closed."));
|
|
1927
1924
|
return;
|
|
1928
1925
|
}
|
|
1929
|
-
const url = authWindow.location.href || "";
|
|
1930
|
-
if (url.startsWith(window.location.origin)) {
|
|
1931
|
-
const result =
|
|
1926
|
+
const url$1 = authWindow.location.href || "";
|
|
1927
|
+
if (url$1.startsWith(window.location.origin)) {
|
|
1928
|
+
const result = url.parseOAuthResponse(url$1, provider);
|
|
1932
1929
|
if (result) {
|
|
1933
1930
|
authWindow.close();
|
|
1934
1931
|
clearInterval(interval);
|
|
1935
|
-
|
|
1932
|
+
completion.completeOAuthPopup({
|
|
1936
1933
|
provider,
|
|
1937
1934
|
publicKey,
|
|
1938
1935
|
result,
|
|
@@ -1988,7 +1985,7 @@ const ClientProvider = ({
|
|
|
1988
1985
|
}
|
|
1989
1986
|
const nonce = utils$1.bytesToHex(sha2.sha256(publicKey));
|
|
1990
1987
|
// Build OAuth URL
|
|
1991
|
-
const authUrl =
|
|
1988
|
+
const authUrl = url.buildOAuthUrl({
|
|
1992
1989
|
provider,
|
|
1993
1990
|
clientId,
|
|
1994
1991
|
redirectUri,
|
|
@@ -1999,12 +1996,12 @@ const ClientProvider = ({
|
|
|
1999
1996
|
});
|
|
2000
1997
|
if (openInPage) {
|
|
2001
1998
|
// Remainder of logic will occur in completeRedirectOauth
|
|
2002
|
-
return
|
|
1999
|
+
return url.redirectToOAuthProvider(authUrl);
|
|
2003
2000
|
}
|
|
2004
2001
|
// Popup flow
|
|
2005
|
-
const authWindow =
|
|
2002
|
+
const authWindow = url.openOAuthPopup();
|
|
2006
2003
|
if (!authWindow) {
|
|
2007
|
-
throw new Error(`Failed to open ${
|
|
2004
|
+
throw new Error(`Failed to open ${helpers.capitalizeProviderName(provider)} login window.`);
|
|
2008
2005
|
}
|
|
2009
2006
|
authWindow.location.href = authUrl;
|
|
2010
2007
|
return new Promise((resolve, reject) => {
|
|
@@ -2015,13 +2012,13 @@ const ClientProvider = ({
|
|
|
2015
2012
|
reject(new Error("Authentication window was closed."));
|
|
2016
2013
|
return;
|
|
2017
2014
|
}
|
|
2018
|
-
const url = authWindow.location.href || "";
|
|
2019
|
-
if (url.startsWith(window.location.origin)) {
|
|
2020
|
-
const result =
|
|
2015
|
+
const url$1 = authWindow.location.href || "";
|
|
2016
|
+
if (url$1.startsWith(window.location.origin)) {
|
|
2017
|
+
const result = url.parseOAuthResponse(url$1, provider);
|
|
2021
2018
|
if (result) {
|
|
2022
2019
|
authWindow.close();
|
|
2023
2020
|
clearInterval(interval);
|
|
2024
|
-
|
|
2021
|
+
completion.completeOAuthPopup({
|
|
2025
2022
|
provider,
|
|
2026
2023
|
publicKey,
|
|
2027
2024
|
result,
|
|
@@ -2066,7 +2063,7 @@ const ClientProvider = ({
|
|
|
2066
2063
|
}
|
|
2067
2064
|
const nonce = utils$1.bytesToHex(sha2.sha256(publicKey));
|
|
2068
2065
|
// Build OAuth URL
|
|
2069
|
-
const authUrl =
|
|
2066
|
+
const authUrl = url.buildOAuthUrl({
|
|
2070
2067
|
provider,
|
|
2071
2068
|
clientId,
|
|
2072
2069
|
redirectUri,
|
|
@@ -2077,12 +2074,12 @@ const ClientProvider = ({
|
|
|
2077
2074
|
});
|
|
2078
2075
|
if (openInPage) {
|
|
2079
2076
|
// Remainder of logic will occur in completeRedirectOauth
|
|
2080
|
-
return
|
|
2077
|
+
return url.redirectToOAuthProvider(authUrl);
|
|
2081
2078
|
}
|
|
2082
2079
|
// Popup flow
|
|
2083
|
-
const authWindow =
|
|
2080
|
+
const authWindow = url.openOAuthPopup();
|
|
2084
2081
|
if (!authWindow) {
|
|
2085
|
-
throw new Error(`Failed to open ${
|
|
2082
|
+
throw new Error(`Failed to open ${helpers.capitalizeProviderName(provider)} login window.`);
|
|
2086
2083
|
}
|
|
2087
2084
|
authWindow.location.href = authUrl;
|
|
2088
2085
|
return new Promise((resolve, reject) => {
|
|
@@ -2093,13 +2090,13 @@ const ClientProvider = ({
|
|
|
2093
2090
|
reject(new Error("Authentication window was closed."));
|
|
2094
2091
|
return;
|
|
2095
2092
|
}
|
|
2096
|
-
const url = authWindow.location.href || "";
|
|
2097
|
-
if (url.startsWith(window.location.origin)) {
|
|
2098
|
-
const result =
|
|
2093
|
+
const url$1 = authWindow.location.href || "";
|
|
2094
|
+
if (url$1.startsWith(window.location.origin)) {
|
|
2095
|
+
const result = url.parseOAuthResponse(url$1, provider);
|
|
2099
2096
|
if (result) {
|
|
2100
2097
|
authWindow.close();
|
|
2101
2098
|
clearInterval(interval);
|
|
2102
|
-
|
|
2099
|
+
completion.completeOAuthPopup({
|
|
2103
2100
|
provider,
|
|
2104
2101
|
publicKey,
|
|
2105
2102
|
result,
|
|
@@ -2146,10 +2143,10 @@ const ClientProvider = ({
|
|
|
2146
2143
|
const {
|
|
2147
2144
|
verifier,
|
|
2148
2145
|
codeChallenge
|
|
2149
|
-
} = await
|
|
2150
|
-
|
|
2146
|
+
} = await pkce.generateChallengePair();
|
|
2147
|
+
storage.storePKCEVerifier(provider, verifier);
|
|
2151
2148
|
// Build OAuth URL
|
|
2152
|
-
const authUrl =
|
|
2149
|
+
const authUrl = url.buildOAuthUrl({
|
|
2153
2150
|
provider,
|
|
2154
2151
|
clientId,
|
|
2155
2152
|
redirectUri,
|
|
@@ -2161,12 +2158,12 @@ const ClientProvider = ({
|
|
|
2161
2158
|
});
|
|
2162
2159
|
if (openInPage) {
|
|
2163
2160
|
// Remainder of logic will occur in completeRedirectOauth
|
|
2164
|
-
return
|
|
2161
|
+
return url.redirectToOAuthProvider(authUrl);
|
|
2165
2162
|
}
|
|
2166
2163
|
// Popup flow
|
|
2167
|
-
const authWindow =
|
|
2164
|
+
const authWindow = url.openOAuthPopup();
|
|
2168
2165
|
if (!authWindow) {
|
|
2169
|
-
throw new Error(`Failed to open ${
|
|
2166
|
+
throw new Error(`Failed to open ${helpers.capitalizeProviderName(provider)} login window.`);
|
|
2170
2167
|
}
|
|
2171
2168
|
authWindow.location.href = authUrl;
|
|
2172
2169
|
return new Promise((resolve, reject) => {
|
|
@@ -2177,13 +2174,13 @@ const ClientProvider = ({
|
|
|
2177
2174
|
reject(new Error("Authentication window was closed."));
|
|
2178
2175
|
return;
|
|
2179
2176
|
}
|
|
2180
|
-
const url = authWindow.location.href || "";
|
|
2181
|
-
if (url.startsWith(window.location.origin)) {
|
|
2182
|
-
const result =
|
|
2177
|
+
const url$1 = authWindow.location.href || "";
|
|
2178
|
+
if (url$1.startsWith(window.location.origin)) {
|
|
2179
|
+
const result = url.parseOAuthResponse(url$1, provider);
|
|
2183
2180
|
if (result) {
|
|
2184
2181
|
authWindow.close();
|
|
2185
2182
|
clearInterval(interval);
|
|
2186
|
-
|
|
2183
|
+
completion.completeOAuthPopup({
|
|
2187
2184
|
provider,
|
|
2188
2185
|
publicKey,
|
|
2189
2186
|
result,
|
|
@@ -2191,7 +2188,7 @@ const ClientProvider = ({
|
|
|
2191
2188
|
completeOauth,
|
|
2192
2189
|
onOauthSuccess: params?.onOauthSuccess,
|
|
2193
2190
|
exchangeCodeForToken: async codeVerifier => {
|
|
2194
|
-
const tokenData = await
|
|
2191
|
+
const tokenData = await pkce.exchangeFacebookCodeForToken(clientId, redirectUri, result.authCode, codeVerifier);
|
|
2195
2192
|
return tokenData.id_token;
|
|
2196
2193
|
}
|
|
2197
2194
|
}).then(() => resolve()).catch(reject);
|
|
@@ -3144,7 +3141,7 @@ const ClientProvider = ({
|
|
|
3144
3141
|
});
|
|
3145
3142
|
};
|
|
3146
3143
|
if (openInPage) {
|
|
3147
|
-
|
|
3144
|
+
storage.storeOAuthAddProviderMetadata({
|
|
3148
3145
|
organizationId,
|
|
3149
3146
|
userId,
|
|
3150
3147
|
...(stampWith && {
|
|
@@ -3154,7 +3151,7 @@ const ClientProvider = ({
|
|
|
3154
3151
|
});
|
|
3155
3152
|
}
|
|
3156
3153
|
const additionalState = openInPage ? {
|
|
3157
|
-
oauthIntent:
|
|
3154
|
+
oauthIntent: storage.OAUTH_INTENT_ADD_PROVIDER,
|
|
3158
3155
|
...(successPageDuration > 0 && {
|
|
3159
3156
|
openModal: "true"
|
|
3160
3157
|
})
|
|
@@ -3428,7 +3425,7 @@ const ClientProvider = ({
|
|
|
3428
3425
|
preventBack: true,
|
|
3429
3426
|
onClose: () => reject(new sdkTypes.TurnkeyError("User canceled the transaction.", sdkTypes.TurnkeyErrorCodes.USER_CANCELED)),
|
|
3430
3427
|
content: jsxRuntime.jsx(SendTransaction.SendTransactionPage, {
|
|
3431
|
-
icon: icon ?? helpers.getChainLogo(caip2),
|
|
3428
|
+
icon: icon ?? helpers$1.getChainLogo(caip2),
|
|
3432
3429
|
action: action,
|
|
3433
3430
|
caip2: caip2,
|
|
3434
3431
|
successPageDuration: successPageDuration,
|
|
@@ -3478,7 +3475,7 @@ const ClientProvider = ({
|
|
|
3478
3475
|
preventBack: true,
|
|
3479
3476
|
onClose: () => reject(new sdkTypes.TurnkeyError("User canceled the transaction.", sdkTypes.TurnkeyErrorCodes.USER_CANCELED)),
|
|
3480
3477
|
content: jsxRuntime.jsx(SendTransaction.SendTransactionPage, {
|
|
3481
|
-
icon: icon ?? helpers.getChainLogo(caip2),
|
|
3478
|
+
icon: icon ?? helpers$1.getChainLogo(caip2),
|
|
3482
3479
|
action: action,
|
|
3483
3480
|
caip2: caip2,
|
|
3484
3481
|
successPageDuration: successPageDuration,
|