@turnkey/core 2.6.0 → 2.7.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.
Files changed (43) hide show
  1. package/dist/__clients__/core.d.ts +21 -2
  2. package/dist/__clients__/core.d.ts.map +1 -1
  3. package/dist/__clients__/core.js +108 -39
  4. package/dist/__clients__/core.js.map +1 -1
  5. package/dist/__clients__/core.mjs +101 -32
  6. package/dist/__clients__/core.mjs.map +1 -1
  7. package/dist/__generated__/sdk-client-base.d.ts +9 -0
  8. package/dist/__generated__/sdk-client-base.d.ts.map +1 -1
  9. package/dist/__generated__/sdk-client-base.js +59 -1
  10. package/dist/__generated__/sdk-client-base.js.map +1 -1
  11. package/dist/__generated__/sdk-client-base.mjs +60 -2
  12. package/dist/__generated__/sdk-client-base.mjs.map +1 -1
  13. package/dist/__generated__/version.d.ts +1 -1
  14. package/dist/__generated__/version.js +1 -1
  15. package/dist/__generated__/version.mjs +1 -1
  16. package/dist/__stampers__/api/base.d.ts +2 -1
  17. package/dist/__stampers__/api/base.d.ts.map +1 -1
  18. package/dist/__stampers__/api/base.js +11 -14
  19. package/dist/__stampers__/api/base.js.map +1 -1
  20. package/dist/__stampers__/api/base.mjs +11 -14
  21. package/dist/__stampers__/api/base.mjs.map +1 -1
  22. package/dist/__stampers__/attested/base.d.ts +22 -0
  23. package/dist/__stampers__/attested/base.d.ts.map +1 -0
  24. package/dist/__stampers__/attested/base.js +50 -0
  25. package/dist/__stampers__/attested/base.js.map +1 -0
  26. package/dist/__stampers__/attested/base.mjs +48 -0
  27. package/dist/__stampers__/attested/base.mjs.map +1 -0
  28. package/dist/__types__/config.d.ts +42 -1
  29. package/dist/__types__/config.d.ts.map +1 -1
  30. package/dist/__types__/enums.d.ts +2 -1
  31. package/dist/__types__/enums.d.ts.map +1 -1
  32. package/dist/__types__/enums.js +1 -0
  33. package/dist/__types__/enums.js.map +1 -1
  34. package/dist/__types__/enums.mjs +1 -0
  35. package/dist/__types__/enums.mjs.map +1 -1
  36. package/dist/__types__/method-types/shared.d.ts +21 -1
  37. package/dist/__types__/method-types/shared.d.ts.map +1 -1
  38. package/dist/utils.d.ts.map +1 -1
  39. package/dist/utils.js +3 -1
  40. package/dist/utils.js.map +1 -1
  41. package/dist/utils.mjs +3 -1
  42. package/dist/utils.mjs.map +1 -1
  43. package/package.json +6 -6
@@ -2,7 +2,7 @@ import { TurnkeySDKClientBase } from '../__generated__/sdk-client-base.mjs';
2
2
  import { TurnkeyErrorCodes, TurnkeyError, AuthAction } from '@turnkey/sdk-types';
3
3
  import { DEFAULT_SESSION_EXPIRATION_IN_SECONDS } from '../__types__/auth.mjs';
4
4
  import { SessionKey, StamperType, WalletSource, FilterType, OtpType, OtpTypeToFilterTypeMap, Curve, Chain, SignIntent } from '../__types__/enums.mjs';
5
- import { withTurnkeyErrorHandling, isValidPasskeyName, isWeb, isReactNative, buildSignUpBody, findWalletProviderFromAddress, getPublicKeyFromStampHeader, addressFromPublicKey, getCurveTypeFromProvider, getClientSignatureMessageForLogin, getClientSignatureMessageForSignup, getAuthenticatorAddresses, fetchAllWalletAccountsWithCursor, mapAccountsToWallet, toExternalTimestamp, isEthereumProvider, isSolanaProvider, getActiveSessionOrThrowIfRequired, getHashFunction, getEncodingType, getEncodedMessage, splitSignature, broadcastTransaction, ERC20_TRANSFER_ABI, getPolicySignature, googleISS, isWalletAccountArray, generateWalletAccountsFromAddressFormat } from '../utils.mjs';
5
+ import { withTurnkeyErrorHandling, isValidPasskeyName, isWeb, isReactNative, buildSignUpBody, findWalletProviderFromAddress, getPublicKeyFromStampHeader, addressFromPublicKey, getCurveTypeFromProvider, decodeVerificationToken, getClientSignatureMessageForSignup, getAuthenticatorAddresses, fetchAllWalletAccountsWithCursor, mapAccountsToWallet, toExternalTimestamp, isEthereumProvider, isSolanaProvider, getActiveSessionOrThrowIfRequired, getHashFunction, getEncodingType, getEncodedMessage, splitSignature, broadcastTransaction, ERC20_TRANSFER_ABI, getPolicySignature, googleISS, isWalletAccountArray, generateWalletAccountsFromAddressFormat } from '../utils.mjs';
6
6
  import { encryptOtpCodeToBundle, verify } from '@turnkey/crypto';
7
7
  import { createStorageManager } from '../__storage__/base.mjs';
8
8
  import { CrossPlatformApiKeyStamper } from '../__stampers__/api/base.mjs';
@@ -13,11 +13,12 @@ import { createWalletManager } from '../__wallet__/base.mjs';
13
13
  import { toUtf8Bytes } from 'ethers';
14
14
  import { SignatureFormat } from '@turnkey/api-key-stamper';
15
15
  import { encodeFunctionData } from 'viem';
16
+ import { AttestedScheme, AttestedStamper } from '../__stampers__/attested/base.mjs';
16
17
 
17
18
  class TurnkeyClient {
18
19
  constructor(config,
19
20
  // Users can pass in their own stampers, or we will create them. Should we remove this?
20
- apiKeyStamper, passkeyStamper, walletManager) {
21
+ apiKeyStamper, passkeyStamper, attestedStamper, walletManager) {
21
22
  /**
22
23
  * Overrides the API key stamper configuration.
23
24
  *
@@ -73,6 +74,58 @@ class TurnkeyClient {
73
74
  errorCode: TurnkeyErrorCodes.INITIALIZE_PASSKEY_STAMPER_ERROR,
74
75
  });
75
76
  };
77
+ /**
78
+ * Overrides the attested stamper with a verification token or OIDC token.
79
+ *
80
+ * - This function updates the attested stamper's identity and automatically sets the correct scheme.
81
+ * - Pass `verificationToken` to set the attestation identity and scheme to STAMP_ATTESTED_SCHEME_P256_VERIFICATION_TOKEN.
82
+ * - Pass `oidcToken` to set the attestation identity and scheme to STAMP_ATTESTED_SCHEME_P256_OIDC.
83
+ * - Only one of `verificationToken` or `oidcToken` can be provided at a time.
84
+ * - If neither token is provided, the attestation identity is cleared.
85
+ * - Useful for dynamically changing the attested identity and scheme used for signing requests.
86
+ *
87
+ * @param params.verificationToken - verification token to use as the attested identity with STAMP_ATTESTED_SCHEME_P256_VERIFICATION_TOKEN scheme.
88
+ * @param params.oidcToken - OIDC token to use as the attested identity with STAMP_ATTESTED_SCHEME_P256_OIDC scheme.
89
+ * @param params.publicKey - public key that signs the attested stamp. Must match the key bound to the token.
90
+ * @returns A promise that resolves when the stamper has been updated.
91
+ * @throws {TurnkeyError} If the attested stamper is not initialized, if both tokens are provided, or if there is an error updating it.
92
+ */
93
+ this.overrideAttestedStamper = async (params) => {
94
+ return withTurnkeyErrorHandling(async () => {
95
+ if (!this.attestedStamper) {
96
+ throw new TurnkeyError("Attested stamper is not initialized", TurnkeyErrorCodes.INTERNAL_ERROR);
97
+ }
98
+ const { verificationToken, oidcToken, publicKey } = params;
99
+ // we enforce that you cannot set both a verificationToken and an oidcToken
100
+ if (verificationToken && oidcToken) {
101
+ throw new TurnkeyError("Cannot set both verificationToken and oidcToken. Please provide only one.", TurnkeyErrorCodes.INVALID_REQUEST);
102
+ }
103
+ // we require a publicKey if either a verificationToken or an oidcToken is provided
104
+ if ((verificationToken || oidcToken) && !publicKey) {
105
+ throw new TurnkeyError("A publicKey must be provided when setting a verificationToken or oidcToken.", TurnkeyErrorCodes.INVALID_REQUEST);
106
+ }
107
+ if (verificationToken) {
108
+ this.attestedStamper.configure({
109
+ attestedIdentity: verificationToken,
110
+ publicKey: publicKey,
111
+ scheme: AttestedScheme.P256_VERIFICATION_TOKEN,
112
+ });
113
+ }
114
+ else if (oidcToken) {
115
+ this.attestedStamper.configure({
116
+ attestedIdentity: oidcToken,
117
+ publicKey: publicKey,
118
+ scheme: AttestedScheme.P256_OIDC,
119
+ });
120
+ }
121
+ else {
122
+ this.attestedStamper.clear();
123
+ }
124
+ }, {
125
+ errorMessage: "Failed to override attested stamper",
126
+ errorCode: TurnkeyErrorCodes.INTERNAL_ERROR,
127
+ });
128
+ };
76
129
  /**
77
130
  * Creates a new TurnkeySDKClientBase instance with the provided configuration.
78
131
  * This method is used internally to create the HTTP client for making API requests,
@@ -104,6 +157,7 @@ class TurnkeyClient {
104
157
  organizationId,
105
158
  apiKeyStamper: this.apiKeyStamper,
106
159
  passkeyStamper: this.passkeyStamper,
160
+ attestedStamper: this.attestedStamper,
107
161
  walletStamper: this.walletManager?.stamper,
108
162
  storageManager: this.storageManager,
109
163
  });
@@ -245,6 +299,7 @@ class TurnkeyClient {
245
299
  };
246
300
  await this.overridePasskeyStamper({ config: mergedConfig });
247
301
  }
302
+ const sessionProfileId = params?.sessionProfileId;
248
303
  if (!generatedPublicKey) {
249
304
  throw new TurnkeyError("A publickey could not be found or generated.", TurnkeyErrorCodes.INTERNAL_ERROR);
250
305
  }
@@ -252,6 +307,7 @@ class TurnkeyClient {
252
307
  publicKey: generatedPublicKey,
253
308
  organizationId: params?.organizationId ?? this.config.organizationId,
254
309
  expirationSeconds,
310
+ ...(sessionProfileId && { sessionProfileId }),
255
311
  };
256
312
  const passkeyLoginRequest = await this.httpClient.stampStampLogin(loginPayload, StamperType.Passkey);
257
313
  if (!passkeyLoginRequest) {
@@ -319,7 +375,7 @@ class TurnkeyClient {
319
375
  * @throws {TurnkeyError} If there is an error during passkey creation, sub-organization creation, or session storage.
320
376
  */
321
377
  this.signUpWithPasskey = async (params) => {
322
- const { passkeyDisplayName, challenge, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, createSubOrgParams, sessionKey = SessionKey.DefaultSessionkey, captchaToken, } = params || {};
378
+ const { passkeyDisplayName, challenge, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, createSubOrgParams, sessionKey = SessionKey.DefaultSessionkey, sessionProfileId, captchaToken, } = params || {};
323
379
  const generatedPublicKey = await this.createApiKeyPair();
324
380
  return withTurnkeyErrorHandling(async () => {
325
381
  if (!this.passkeyStamper) {
@@ -368,6 +424,7 @@ class TurnkeyClient {
368
424
  publicKey: newGeneratedKeyPair,
369
425
  organizationId: res.organizationId,
370
426
  expirationSeconds,
427
+ ...(sessionProfileId && { sessionProfileId }),
371
428
  });
372
429
  await this.storeSession({
373
430
  sessionToken: sessionResponse.session,
@@ -526,7 +583,7 @@ class TurnkeyClient {
526
583
  * or the public key cannot be derived or generated.
527
584
  */
528
585
  this.buildWalletLoginRequest = async (params) => {
529
- const { walletProvider, publicKey: providedPublicKey } = params;
586
+ const { walletProvider, publicKey: providedPublicKey, sessionProfileId, } = params;
530
587
  const expirationSeconds = params.expirationSeconds || DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
531
588
  const futureSessionPublicKey = providedPublicKey ?? (await this.createApiKeyPair());
532
589
  return withTurnkeyErrorHandling(async () => {
@@ -545,6 +602,7 @@ class TurnkeyClient {
545
602
  publicKey: futureSessionPublicKey,
546
603
  organizationId: this.config.organizationId,
547
604
  expirationSeconds,
605
+ ...(sessionProfileId && { sessionProfileId }),
548
606
  }, StamperType.Wallet);
549
607
  }, {
550
608
  errorMessage: "Failed to create stamped request for wallet login",
@@ -887,34 +945,27 @@ class TurnkeyClient {
887
945
  * @throws {TurnkeyError} If there is an error during the OTP login process or if key pair cleanup fails.
888
946
  */
889
947
  this.loginWithOtp = async (params) => {
890
- const { verificationToken, invalidateExisting = false, organizationId, sessionKey = SessionKey.DefaultSessionkey, } = params;
948
+ const { verificationToken, invalidateExisting = false, organizationId, sessionKey = SessionKey.DefaultSessionkey, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, sessionProfileId, } = params;
891
949
  return withTurnkeyErrorHandling(async () => {
892
- const { message, publicKey: verificationPublicKey } = getClientSignatureMessageForLogin({ verificationToken });
893
- // we sign with the verification token key. This is the key bound during
894
- // verifyOtp() and is what Turnkey expects to sign the client signature for login
895
- const signature = await this.signWithApiKey({
896
- message,
897
- publicKey: verificationPublicKey,
898
- });
899
- if (!signature) {
900
- throw new TurnkeyError(`Failed to sign client signature for OTP login`, TurnkeyErrorCodes.INTERNAL_ERROR);
950
+ const { public_key: verificationPublicKey } = decodeVerificationToken(verificationToken);
951
+ if (!verificationPublicKey) {
952
+ throw new TurnkeyError("Invalid verification token: missing publicKey", TurnkeyErrorCodes.INVALID_REQUEST);
901
953
  }
902
- const clientSignature = {
903
- message: message,
954
+ // We override the attested stamper with the verification token so the stampLogin request can be stamped with it.
955
+ await this.overrideAttestedStamper({
956
+ verificationToken,
904
957
  publicKey: verificationPublicKey,
905
- scheme: "CLIENT_SIGNATURE_SCHEME_API_P256",
906
- signature: signature,
907
- };
958
+ });
908
959
  // the verification token's public key is also used as the session public key for login
909
- const loginRes = await this.httpClient.proxyOtpLoginV2({
910
- verificationToken,
960
+ const loginRes = await this.httpClient.stampLogin({
911
961
  publicKey: verificationPublicKey,
912
- clientSignature,
962
+ expirationSeconds,
913
963
  invalidateExisting,
914
964
  ...(organizationId && { organizationId }),
915
- });
965
+ ...(sessionProfileId && { sessionProfileId }),
966
+ }, StamperType.Attested);
916
967
  if (!loginRes) {
917
- throw new TurnkeyError(`Auth proxy OTP login failed`, TurnkeyErrorCodes.OTP_LOGIN_ERROR);
968
+ throw new TurnkeyError(`OTP login failed`, TurnkeyErrorCodes.OTP_LOGIN_ERROR);
918
969
  }
919
970
  if (!loginRes.session) {
920
971
  throw new TurnkeyError("No session returned from OTP login", TurnkeyErrorCodes.OTP_LOGIN_ERROR);
@@ -952,7 +1003,7 @@ class TurnkeyClient {
952
1003
  * @throws {TurnkeyError} If there is an error during the OTP sign-up process or session storage.
953
1004
  */
954
1005
  this.signUpWithOtp = async (params) => {
955
- const { verificationToken, contact, otpType, createSubOrgParams, invalidateExisting, sessionKey, captchaToken, } = params;
1006
+ const { verificationToken, contact, otpType, createSubOrgParams, invalidateExisting, sessionKey, sessionProfileId, captchaToken, } = params;
956
1007
  // build sign up body without client signature first
957
1008
  const signUpBody = buildSignUpBody({
958
1009
  createSubOrgParams: {
@@ -1000,6 +1051,7 @@ class TurnkeyClient {
1000
1051
  verificationToken,
1001
1052
  ...(invalidateExisting && { invalidateExisting }),
1002
1053
  ...(sessionKey && { sessionKey }),
1054
+ ...(sessionProfileId && { sessionProfileId }),
1003
1055
  });
1004
1056
  return {
1005
1057
  ...otpRes,
@@ -1037,7 +1089,7 @@ class TurnkeyClient {
1037
1089
  * @throws {TurnkeyError} If there is an error during OTP verification, sign-up, or login.
1038
1090
  */
1039
1091
  this.completeOtp = async (params) => {
1040
- const { otpId, otpCode, otpEncryptionTargetBundle, contact, otpType, invalidateExisting = false, sessionKey, createSubOrgParams, captchaToken, } = params;
1092
+ const { otpId, otpCode, otpEncryptionTargetBundle, contact, otpType, invalidateExisting = false, sessionKey, createSubOrgParams, sessionProfileId, captchaToken, } = params;
1041
1093
  const publicKey = params.publicKey ?? (await this.createApiKeyPair());
1042
1094
  if (!publicKey) {
1043
1095
  throw new TurnkeyError("No public key available. Either pass a publicKey or ensure apiKeyStamper is configured.", TurnkeyErrorCodes.INVALID_REQUEST);
@@ -1069,6 +1121,7 @@ class TurnkeyClient {
1069
1121
  ...(createSubOrgParams && { createSubOrgParams }),
1070
1122
  ...(invalidateExisting && { invalidateExisting }),
1071
1123
  ...(sessionKey && { sessionKey }),
1124
+ ...(sessionProfileId && { sessionProfileId }),
1072
1125
  ...(captchaToken && { captchaToken }),
1073
1126
  });
1074
1127
  return {
@@ -1082,6 +1135,7 @@ class TurnkeyClient {
1082
1135
  verificationToken,
1083
1136
  ...(invalidateExisting && { invalidateExisting }),
1084
1137
  ...(sessionKey && { sessionKey }),
1138
+ ...(sessionProfileId && { sessionProfileId }),
1085
1139
  });
1086
1140
  return {
1087
1141
  ...loginRes,
@@ -1127,7 +1181,7 @@ class TurnkeyClient {
1127
1181
  * @throws {TurnkeyError} If there is an error during the OAuth completion process, such as account lookup, sign-up, or login.
1128
1182
  */
1129
1183
  this.completeOauth = async (params) => {
1130
- const { oidcToken, publicKey, providerName, createSubOrgParams, invalidateExisting, sessionKey, captchaToken, } = params;
1184
+ const { oidcToken, publicKey, providerName, createSubOrgParams, invalidateExisting, sessionKey, sessionProfileId, captchaToken, } = params;
1131
1185
  return withTurnkeyErrorHandling(async () => {
1132
1186
  const accountRes = await this.httpClient.proxyGetAccount({
1133
1187
  filterType: "OIDC_TOKEN",
@@ -1143,6 +1197,7 @@ class TurnkeyClient {
1143
1197
  publicKey,
1144
1198
  ...(invalidateExisting && { invalidateExisting }),
1145
1199
  ...(sessionKey && { sessionKey }),
1200
+ ...(sessionProfileId && { sessionProfileId }),
1146
1201
  });
1147
1202
  return {
1148
1203
  ...loginRes,
@@ -1161,6 +1216,7 @@ class TurnkeyClient {
1161
1216
  }),
1162
1217
  ...(invalidateExisting && { invalidateExisting }),
1163
1218
  ...(sessionKey && { sessionKey }),
1219
+ ...(sessionProfileId && { sessionProfileId }),
1164
1220
  ...(captchaToken && { captchaToken }),
1165
1221
  });
1166
1222
  return {
@@ -1193,19 +1249,25 @@ class TurnkeyClient {
1193
1249
  * @throws {TurnkeyError} If there is an error during the OAuth login process or if key pair cleanup fails.
1194
1250
  */
1195
1251
  this.loginWithOauth = async (params) => {
1196
- const { oidcToken, publicKey, organizationId, invalidateExisting = false, sessionKey = SessionKey.DefaultSessionkey, } = params;
1252
+ const { oidcToken, publicKey, organizationId, invalidateExisting = false, sessionKey = SessionKey.DefaultSessionkey, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, sessionProfileId, } = params;
1197
1253
  return withTurnkeyErrorHandling(async () => {
1198
1254
  if (!publicKey) {
1199
1255
  throw new TurnkeyError("Public key must be provided to log in with OAuth. Please create a key pair first.", TurnkeyErrorCodes.MISSING_PARAMS);
1200
1256
  }
1201
- const loginRes = await this.httpClient.proxyOAuthLogin({
1257
+ // We override the attested stamper with the oidcToken so the stampLogin request can be stamped with it.
1258
+ await this.overrideAttestedStamper({
1202
1259
  oidcToken,
1203
1260
  publicKey,
1261
+ });
1262
+ const loginRes = await this.httpClient.stampLogin({
1263
+ publicKey,
1264
+ expirationSeconds,
1204
1265
  invalidateExisting,
1205
1266
  ...(organizationId && { organizationId }),
1206
- });
1267
+ ...(sessionProfileId && { sessionProfileId }),
1268
+ }, StamperType.Attested);
1207
1269
  if (!loginRes) {
1208
- throw new TurnkeyError(`Auth proxy OAuth login failed`, TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
1270
+ throw new TurnkeyError(`OAuth login failed`, TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
1209
1271
  }
1210
1272
  if (!loginRes.session) {
1211
1273
  throw new TurnkeyError("No session returned from oauth login", TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
@@ -1256,7 +1318,7 @@ class TurnkeyClient {
1256
1318
  * @throws {TurnkeyError} If there is an error during the OAuth sign-up or login process.
1257
1319
  */
1258
1320
  this.signUpWithOauth = async (params) => {
1259
- const { oidcToken, publicKey, providerName = "OpenID Connect Provider" + " " + Date.now(), createSubOrgParams, sessionKey, captchaToken, } = params;
1321
+ const { oidcToken, publicKey, providerName = "OpenID Connect Provider" + " " + Date.now(), createSubOrgParams, sessionKey, sessionProfileId, captchaToken, } = params;
1260
1322
  return withTurnkeyErrorHandling(async () => {
1261
1323
  const signUpBody = buildSignUpBody({
1262
1324
  createSubOrgParams: {
@@ -1278,6 +1340,7 @@ class TurnkeyClient {
1278
1340
  oidcToken,
1279
1341
  publicKey: publicKey,
1280
1342
  ...(sessionKey && { sessionKey }),
1343
+ ...(sessionProfileId && { sessionProfileId }),
1281
1344
  });
1282
1345
  return {
1283
1346
  ...oauthRes,
@@ -3135,6 +3198,9 @@ class TurnkeyClient {
3135
3198
  publicKey: keyPair,
3136
3199
  expirationSeconds,
3137
3200
  invalidateExisting: invalidateExisitng,
3201
+ ...(session.sessionProfileId && {
3202
+ sessionProfileId: session.sessionProfileId,
3203
+ }),
3138
3204
  }, stampWith);
3139
3205
  if (!res || !res.session) {
3140
3206
  throw new TurnkeyError("No session found in the refresh response", TurnkeyErrorCodes.BAD_RESPONSE);
@@ -3500,6 +3566,7 @@ class TurnkeyClient {
3500
3566
  // Just store any explicitly provided stampers
3501
3567
  this.apiKeyStamper = apiKeyStamper;
3502
3568
  this.passkeyStamper = passkeyStamper;
3569
+ this.attestedStamper = attestedStamper;
3503
3570
  this.walletManager = walletManager;
3504
3571
  // Actual initialization will happen in init()
3505
3572
  }
@@ -3509,6 +3576,8 @@ class TurnkeyClient {
3509
3576
  this.storageManager = await createStorageManager();
3510
3577
  // Initialize the API key stamper
3511
3578
  this.apiKeyStamper = new CrossPlatformApiKeyStamper(this.storageManager);
3579
+ // Then use it to initialize the attested stamper
3580
+ this.attestedStamper = new AttestedStamper(this.apiKeyStamper);
3512
3581
  // we parallelize independent initializations:
3513
3582
  // - API key stamper init
3514
3583
  // - Passkey stamper creation and init (if configured)