@txnlab/use-wallet-web3auth 5.0.0-rc.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TxnLab, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,253 @@
1
+ import algosdk from "algosdk";
2
+ import { AdapterConstructorParams, BaseWallet, WalletAccount, WalletMetadata } from "@txnlab/use-wallet/adapter";
3
+ import { WalletAdapterConfig } from "@txnlab/use-wallet";
4
+
5
+ //#region src/adapter.d.ts
6
+ /**
7
+ * Parameters for custom authentication (e.g., Firebase, custom JWT)
8
+ */
9
+ interface Web3AuthCustomAuth {
10
+ /**
11
+ * Custom verifier name configured in Web3Auth dashboard
12
+ */
13
+ verifier: string;
14
+ /**
15
+ * User identifier (e.g., email, Firebase UID)
16
+ */
17
+ verifierId: string;
18
+ /**
19
+ * JWT token from your authentication provider (e.g., Firebase ID token)
20
+ */
21
+ idToken: string;
22
+ }
23
+ /**
24
+ * Credentials returned by getAuthCredentials callback
25
+ */
26
+ interface Web3AuthCredentials {
27
+ /**
28
+ * JWT token from your authentication provider (e.g., Firebase ID token)
29
+ */
30
+ idToken: string;
31
+ /**
32
+ * User identifier (e.g., email, Firebase UID)
33
+ */
34
+ verifierId: string;
35
+ /**
36
+ * Custom verifier name (optional, uses options.verifier if not provided)
37
+ */
38
+ verifier?: string;
39
+ }
40
+ /**
41
+ * Web3Auth configuration options
42
+ */
43
+ interface Web3AuthOptions {
44
+ /**
45
+ * Web3Auth Client ID from the dashboard
46
+ * @see https://dashboard.web3auth.io
47
+ */
48
+ clientId: string;
49
+ /**
50
+ * Web3Auth network (mainnet, testnet, sapphire_mainnet, sapphire_devnet, cyan, aqua)
51
+ * @default 'sapphire_mainnet'
52
+ */
53
+ web3AuthNetwork?: 'mainnet' | 'testnet' | 'sapphire_mainnet' | 'sapphire_devnet' | 'cyan' | 'aqua';
54
+ /**
55
+ * Login provider to use (google, facebook, twitter, discord, etc.)
56
+ * If not specified, the Web3Auth modal will be shown
57
+ */
58
+ loginProvider?: 'google' | 'facebook' | 'twitter' | 'discord' | 'reddit' | 'twitch' | 'apple' | 'line' | 'github' | 'kakao' | 'linkedin' | 'weibo' | 'wechat' | 'email_passwordless' | 'sms_passwordless';
59
+ /**
60
+ * Login hint for email_passwordless or sms_passwordless
61
+ */
62
+ loginHint?: string;
63
+ /**
64
+ * UI configuration for the Web3Auth modal
65
+ */
66
+ uiConfig?: {
67
+ appName?: string;
68
+ appUrl?: string;
69
+ logoLight?: string;
70
+ logoDark?: string;
71
+ defaultLanguage?: string;
72
+ mode?: 'light' | 'dark' | 'auto';
73
+ theme?: Record<string, string>;
74
+ };
75
+ /**
76
+ * Whether to use the popup flow instead of redirect
77
+ * @default true
78
+ */
79
+ usePopup?: boolean;
80
+ /**
81
+ * Default verifier name for custom authentication.
82
+ * When set, connect() can be called with just { idToken, verifierId }
83
+ */
84
+ verifier?: string;
85
+ /**
86
+ * Callback to get fresh authentication credentials when session expires.
87
+ * Required for automatic re-authentication with Single Factor Auth (SFA).
88
+ *
89
+ * If not provided and the session expires, signTransactions() will throw
90
+ * an error requiring the user to call connect() with fresh credentials.
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * getAuthCredentials: async () => {
95
+ * const user = firebase.auth().currentUser
96
+ * if (!user) throw new Error('Not logged in')
97
+ * const idToken = await user.getIdToken(true)
98
+ * return { idToken, verifierId: user.email || user.uid }
99
+ * }
100
+ * ```
101
+ */
102
+ getAuthCredentials?: () => Promise<Web3AuthCredentials>;
103
+ }
104
+ declare class Web3AuthAdapter extends BaseWallet<Web3AuthOptions> {
105
+ private web3auth;
106
+ private web3authSFA;
107
+ private userInfo;
108
+ /**
109
+ * SECURITY: We store only the address, NEVER the private key.
110
+ * Keys are fetched fresh from Web3Auth and immediately cleared after use.
111
+ */
112
+ private _address;
113
+ /** Track which SDK is currently in use */
114
+ private usingSFA;
115
+ constructor(params: AdapterConstructorParams<Web3AuthOptions>);
116
+ static defaultMetadata: WalletMetadata;
117
+ private loadMetadata;
118
+ private saveMetadata;
119
+ private clearMetadata;
120
+ /**
121
+ * Initialize the Web3Auth client (v10 Modal SDK)
122
+ */
123
+ private initializeClient;
124
+ /**
125
+ * Initialize the Web3Auth Single Factor Auth client for custom JWT authentication.
126
+ * SFA SDK is still at v9 and requires CommonPrivateKeyProvider with chain config.
127
+ */
128
+ private initializeSFAClient;
129
+ /**
130
+ * SECURITY: Fetch the private key from Web3Auth and return it in a SecureKeyContainer.
131
+ * The caller MUST call container.clear() when done.
132
+ *
133
+ * @returns SecureKeyContainer holding the private key
134
+ */
135
+ private getSecureKey;
136
+ /**
137
+ * Convert a hex string to Uint8Array
138
+ */
139
+ private hexToBytes;
140
+ /**
141
+ * Check if Web3Auth is currently connected with a valid session
142
+ */
143
+ private isWeb3AuthConnected;
144
+ /**
145
+ * Ensure Web3Auth is connected and ready for signing.
146
+ * Re-authenticates if the session has expired.
147
+ *
148
+ * This is called lazily when signTransactions() is invoked.
149
+ */
150
+ private ensureConnected;
151
+ /**
152
+ * Re-authenticate using Single Factor Auth (Firebase, custom JWT)
153
+ *
154
+ * Requires getAuthCredentials callback to be configured in options.
155
+ * If the callback returns credentials for a different user, this will
156
+ * disconnect the current wallet (the user logged out and back in as someone else).
157
+ */
158
+ private reconnectSFA;
159
+ /**
160
+ * Re-authenticate using the Web3Auth modal
161
+ *
162
+ * Shows the Web3Auth login modal for the user to authenticate again.
163
+ * If they log in as a different user, this will disconnect the current wallet.
164
+ */
165
+ private reconnectModal;
166
+ /**
167
+ * Verify that the current Web3Auth session matches the cached address.
168
+ *
169
+ * If the address doesn't match (user logged in as someone else),
170
+ * this disconnects the wallet entirely -- it's a different identity.
171
+ */
172
+ private verifyAddressMatch;
173
+ /**
174
+ * Connect to Web3Auth
175
+ *
176
+ * @param args - Optional connection arguments
177
+ * @param args.idToken - JWT token for custom authentication (e.g., Firebase ID token)
178
+ * @param args.verifierId - User identifier for custom authentication (e.g., email, uid)
179
+ * @param args.verifier - Custom verifier name (uses options.verifier if not provided)
180
+ *
181
+ * @example
182
+ * // Standard modal connection
183
+ * await wallet.connect()
184
+ *
185
+ * @example
186
+ * // Custom authentication with Firebase
187
+ * await wallet.connect({
188
+ * idToken: firebaseIdToken,
189
+ * verifierId: user.email,
190
+ * verifier: 'my-firebase-verifier'
191
+ * })
192
+ */
193
+ connect: (args?: Record<string, any>) => Promise<WalletAccount[]>;
194
+ /**
195
+ * Disconnect from Web3Auth
196
+ */
197
+ disconnect: () => Promise<void>;
198
+ /**
199
+ * Resume session from cached state
200
+ *
201
+ * LAZY AUTHENTICATION: We do NOT connect to Web3Auth here.
202
+ * We simply restore the cached address from localStorage.
203
+ * Web3Auth connection is deferred until signTransactions() is called.
204
+ */
205
+ resumeSession: () => Promise<void>;
206
+ canUsePrivateKey: boolean;
207
+ /**
208
+ * Provide scoped access to the private key via a callback.
209
+ *
210
+ * The callback receives a 64-byte Algorand secret key (ed25519 seed + public key).
211
+ * The key is a fresh copy that is guaranteed to be zeroed from memory when the
212
+ * callback completes, whether it succeeds or throws.
213
+ *
214
+ * SECURITY: The key is fetched fresh from Web3Auth for each call and never cached.
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * const result = await wallet.withPrivateKey(async (secretKey) => {
219
+ * // secretKey is a 64-byte Uint8Array
220
+ * // Use for custom signing, authentication, etc.
221
+ * return doSomethingWith(secretKey)
222
+ * })
223
+ * // secretKey is zeroed at this point
224
+ * ```
225
+ */
226
+ withPrivateKey: <T>(callback: (secretKey: Uint8Array) => Promise<T>) => Promise<T>;
227
+ /**
228
+ * Process transactions for signing
229
+ */
230
+ private processTxns;
231
+ /**
232
+ * Process encoded transactions for signing
233
+ */
234
+ private processEncodedTxns;
235
+ /**
236
+ * Sign transactions
237
+ *
238
+ * LAZY AUTHENTICATION: If the Web3Auth session has expired, this will
239
+ * automatically re-authenticate before signing.
240
+ *
241
+ * SECURITY: The private key is fetched fresh, used for signing,
242
+ * and immediately cleared from memory. The key is never stored
243
+ * between signing operations.
244
+ */
245
+ signTransactions: <T extends algosdk.Transaction[] | Uint8Array[]>(txnGroup: T | T[], indexesToSign?: number[]) => Promise<(Uint8Array | null)[]>;
246
+ }
247
+ //#endregion
248
+ //#region src/index.d.ts
249
+ declare const WALLET_ID: "web3auth";
250
+ declare function web3auth(options: Web3AuthOptions): WalletAdapterConfig;
251
+ //#endregion
252
+ export { WALLET_ID, Web3AuthAdapter, type Web3AuthCredentials, type Web3AuthCustomAuth, type Web3AuthOptions, web3auth };
253
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,545 @@
1
+ import algosdk from "algosdk";
2
+ import { BaseWallet, SecureKeyContainer, deriveAlgorandAccountFromEd25519, flattenTxnGroup, isSignedTxn, isTransactionArray, zeroMemory } from "@txnlab/use-wallet/adapter";
3
+ //#region src/icon.ts
4
+ const icon = `
5
+ <svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
6
+ <rect fill="#0364FF" width="40" height="40" rx="8"/>
7
+ <path fill="#FFFFFF" d="M20 8c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12S26.627 8 20 8zm0 21.6c-5.302 0-9.6-4.298-9.6-9.6S14.698 10.4 20 10.4s9.6 4.298 9.6 9.6-4.298 9.6-9.6 9.6zm0-16.8c-3.976 0-7.2 3.224-7.2 7.2s3.224 7.2 7.2 7.2 7.2-3.224 7.2-7.2-3.224-7.2-7.2-7.2zm0 12c-2.651 0-4.8-2.149-4.8-4.8s2.149-4.8 4.8-4.8 4.8 2.149 4.8 4.8-2.149 4.8-4.8 4.8z"/>
8
+ </svg>
9
+ `;
10
+ //#endregion
11
+ //#region src/adapter.ts
12
+ /**
13
+ * Web3Auth Wallet Adapter for Algorand
14
+ *
15
+ * SECURITY CONSIDERATIONS:
16
+ * - Web3Auth exposes the raw private key for non-EVM chains like Algorand
17
+ * - This implementation uses SecureKeyContainer to minimize key exposure
18
+ * - Keys are never persisted to localStorage or any storage
19
+ * - Keys are cleared from memory immediately after signing operations
20
+ * - Session resumption requires re-authentication (keys are not cached)
21
+ *
22
+ * @see https://web3auth.io/docs
23
+ */
24
+ const LOCAL_STORAGE_WEB3AUTH_KEY = "@txnlab/use-wallet:v5:web3auth";
25
+ const ICON = `data:image/svg+xml;base64,${btoa(icon)}`;
26
+ var Web3AuthAdapter = class extends BaseWallet {
27
+ web3auth = null;
28
+ web3authSFA = null;
29
+ userInfo = null;
30
+ /**
31
+ * SECURITY: We store only the address, NEVER the private key.
32
+ * Keys are fetched fresh from Web3Auth and immediately cleared after use.
33
+ */
34
+ _address = null;
35
+ /** Track which SDK is currently in use */
36
+ usingSFA = false;
37
+ constructor(params) {
38
+ super(params);
39
+ if (!params.options?.clientId) {
40
+ this.logger.error("Missing required option: clientId");
41
+ throw new Error("Missing required option: clientId");
42
+ }
43
+ this.options = {
44
+ web3AuthNetwork: "sapphire_mainnet",
45
+ usePopup: true,
46
+ ...params.options
47
+ };
48
+ }
49
+ static defaultMetadata = {
50
+ name: "Web3Auth",
51
+ icon: ICON
52
+ };
53
+ loadMetadata() {
54
+ if (typeof localStorage === "undefined") return null;
55
+ const data = localStorage.getItem(LOCAL_STORAGE_WEB3AUTH_KEY);
56
+ if (!data) return null;
57
+ try {
58
+ return JSON.parse(data);
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+ saveMetadata() {
64
+ if (typeof localStorage === "undefined") return;
65
+ const metadata = { usingSFA: this.usingSFA };
66
+ localStorage.setItem(LOCAL_STORAGE_WEB3AUTH_KEY, JSON.stringify(metadata));
67
+ }
68
+ clearMetadata() {
69
+ if (typeof localStorage === "undefined") return;
70
+ localStorage.removeItem(LOCAL_STORAGE_WEB3AUTH_KEY);
71
+ }
72
+ /**
73
+ * Initialize the Web3Auth client (v10 Modal SDK)
74
+ */
75
+ async initializeClient() {
76
+ this.logger.info("Initializing Web3Auth client...");
77
+ let Web3Auth;
78
+ let WEB3AUTH_NETWORK;
79
+ try {
80
+ const modal = await import("@web3auth/modal");
81
+ Web3Auth = modal.Web3Auth;
82
+ WEB3AUTH_NETWORK = modal.WEB3AUTH_NETWORK;
83
+ } catch (error) {
84
+ this.logger.error("Failed to load Web3Auth.", error);
85
+ throw new Error("Web3Auth package not found. Please install @web3auth/modal");
86
+ }
87
+ const networkMap = {
88
+ mainnet: WEB3AUTH_NETWORK.MAINNET,
89
+ testnet: WEB3AUTH_NETWORK.TESTNET,
90
+ sapphire_mainnet: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
91
+ sapphire_devnet: WEB3AUTH_NETWORK.SAPPHIRE_DEVNET,
92
+ cyan: WEB3AUTH_NETWORK.CYAN,
93
+ aqua: WEB3AUTH_NETWORK.AQUA
94
+ };
95
+ const web3auth = new Web3Auth({
96
+ clientId: this.options.clientId,
97
+ web3AuthNetwork: networkMap[this.options.web3AuthNetwork || "sapphire_mainnet"],
98
+ uiConfig: this.options.uiConfig
99
+ });
100
+ await web3auth.init();
101
+ this.web3auth = web3auth;
102
+ this.logger.info("Web3Auth client initialized");
103
+ return web3auth;
104
+ }
105
+ /**
106
+ * Initialize the Web3Auth Single Factor Auth client for custom JWT authentication.
107
+ * SFA SDK is still at v9 and requires CommonPrivateKeyProvider with chain config.
108
+ */
109
+ async initializeSFAClient() {
110
+ this.logger.info("Initializing Web3Auth Single Factor Auth client...");
111
+ let Web3Auth;
112
+ let WEB3AUTH_NETWORK;
113
+ let CommonPrivateKeyProvider;
114
+ try {
115
+ Web3Auth = (await import("@web3auth/single-factor-auth")).Web3Auth;
116
+ WEB3AUTH_NETWORK = (await import("@web3auth/modal")).WEB3AUTH_NETWORK;
117
+ CommonPrivateKeyProvider = (await import("@web3auth/base-provider")).CommonPrivateKeyProvider;
118
+ } catch {
119
+ this.logger.error("Failed to load Web3Auth SFA. Make sure @web3auth/single-factor-auth and @web3auth/base-provider are installed.");
120
+ throw new Error("Web3Auth SFA packages not found. Please install @web3auth/single-factor-auth and @web3auth/base-provider");
121
+ }
122
+ const chainConfig = {
123
+ chainNamespace: "other",
124
+ chainId: "algorand",
125
+ rpcTarget: "https://mainnet-api.algonode.cloud",
126
+ displayName: "Algorand",
127
+ blockExplorerUrl: "https://lora.algokit.io/mainnet",
128
+ ticker: "ALGO",
129
+ tickerName: "Algorand"
130
+ };
131
+ const networkMap = {
132
+ mainnet: WEB3AUTH_NETWORK.MAINNET,
133
+ testnet: WEB3AUTH_NETWORK.TESTNET,
134
+ sapphire_mainnet: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
135
+ sapphire_devnet: WEB3AUTH_NETWORK.SAPPHIRE_DEVNET,
136
+ cyan: WEB3AUTH_NETWORK.CYAN,
137
+ aqua: WEB3AUTH_NETWORK.AQUA
138
+ };
139
+ const privateKeyProvider = new CommonPrivateKeyProvider({ config: { chainConfig } });
140
+ const web3authSFA = new Web3Auth({
141
+ clientId: this.options.clientId,
142
+ web3AuthNetwork: networkMap[this.options.web3AuthNetwork || "sapphire_mainnet"],
143
+ privateKeyProvider
144
+ });
145
+ await web3authSFA.init();
146
+ this.web3authSFA = web3authSFA;
147
+ this.logger.info("Web3Auth SFA client initialized");
148
+ return web3authSFA;
149
+ }
150
+ /**
151
+ * SECURITY: Fetch the private key from Web3Auth and return it in a SecureKeyContainer.
152
+ * The caller MUST call container.clear() when done.
153
+ *
154
+ * @returns SecureKeyContainer holding the private key
155
+ */
156
+ async getSecureKey() {
157
+ const provider = this.usingSFA ? this.web3authSFA?.provider : this.web3auth?.provider;
158
+ if (!provider) throw new Error("Web3Auth not connected");
159
+ this.logger.debug("Fetching private key from Web3Auth...");
160
+ const privateKeyHex = await provider.request({ method: "private_key" });
161
+ if (!privateKeyHex || typeof privateKeyHex !== "string") throw new Error("Failed to retrieve private key from Web3Auth");
162
+ const privateKeyBytes = this.hexToBytes(privateKeyHex);
163
+ const container = new SecureKeyContainer(privateKeyBytes);
164
+ zeroMemory(privateKeyBytes);
165
+ this.logger.debug("Private key retrieved and secured");
166
+ return container;
167
+ }
168
+ /**
169
+ * Convert a hex string to Uint8Array
170
+ */
171
+ hexToBytes(hex) {
172
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
173
+ const bytes = new Uint8Array(cleanHex.length / 2);
174
+ for (let i = 0; i < cleanHex.length; i += 2) bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
175
+ return bytes;
176
+ }
177
+ /**
178
+ * Check if Web3Auth is currently connected with a valid session
179
+ */
180
+ isWeb3AuthConnected() {
181
+ if (this.usingSFA) return Boolean(this.web3authSFA?.connected && this.web3authSFA?.provider);
182
+ return Boolean(this.web3auth?.connected && this.web3auth?.provider);
183
+ }
184
+ /**
185
+ * Ensure Web3Auth is connected and ready for signing.
186
+ * Re-authenticates if the session has expired.
187
+ *
188
+ * This is called lazily when signTransactions() is invoked.
189
+ */
190
+ async ensureConnected() {
191
+ if (this.isWeb3AuthConnected()) {
192
+ this.logger.debug("Web3Auth session still valid");
193
+ return;
194
+ }
195
+ this.logger.info("Web3Auth session expired or not initialized, re-authenticating...");
196
+ if (this.usingSFA) await this.reconnectSFA();
197
+ else await this.reconnectModal();
198
+ }
199
+ /**
200
+ * Re-authenticate using Single Factor Auth (Firebase, custom JWT)
201
+ *
202
+ * Requires getAuthCredentials callback to be configured in options.
203
+ * If the callback returns credentials for a different user, this will
204
+ * disconnect the current wallet (the user logged out and back in as someone else).
205
+ */
206
+ async reconnectSFA() {
207
+ if (!this.options.getAuthCredentials) {
208
+ this.logger.error("Cannot re-authenticate: getAuthCredentials callback not configured");
209
+ throw new Error("Web3Auth session expired. Configure getAuthCredentials option for automatic re-auth, or call disconnect() and connect() with fresh credentials.");
210
+ }
211
+ this.logger.info("Getting fresh credentials for SFA re-authentication...");
212
+ let credentials;
213
+ try {
214
+ credentials = await this.options.getAuthCredentials();
215
+ } catch (error) {
216
+ this.logger.warn("Failed to get auth credentials, user may have logged out:", error.message);
217
+ this.onDisconnect();
218
+ throw new Error("Authentication provider session expired. Please log in again.");
219
+ }
220
+ const web3authSFA = this.web3authSFA || await this.initializeSFAClient();
221
+ if (web3authSFA.connected) try {
222
+ await web3authSFA.logout();
223
+ } catch {}
224
+ const verifier = credentials.verifier || this.options.verifier;
225
+ if (!verifier) throw new Error("No verifier configured for SFA authentication");
226
+ if (!await web3authSFA.connect({
227
+ verifier,
228
+ verifierId: credentials.verifierId,
229
+ idToken: credentials.idToken
230
+ })) throw new Error("Failed to re-authenticate with Web3Auth SFA");
231
+ this.usingSFA = true;
232
+ this.saveMetadata();
233
+ await this.verifyAddressMatch();
234
+ }
235
+ /**
236
+ * Re-authenticate using the Web3Auth modal
237
+ *
238
+ * Shows the Web3Auth login modal for the user to authenticate again.
239
+ * If they log in as a different user, this will disconnect the current wallet.
240
+ */
241
+ async reconnectModal() {
242
+ this.logger.info("Showing Web3Auth modal for re-authentication...");
243
+ const web3auth = this.web3auth || await this.initializeClient();
244
+ if (web3auth.connected) try {
245
+ await web3auth.logout();
246
+ } catch {}
247
+ if (!await web3auth.connect()) throw new Error("Re-authentication cancelled or failed");
248
+ this.usingSFA = false;
249
+ this.saveMetadata();
250
+ this.userInfo = await web3auth.getUserInfo();
251
+ await this.verifyAddressMatch();
252
+ }
253
+ /**
254
+ * Verify that the current Web3Auth session matches the cached address.
255
+ *
256
+ * If the address doesn't match (user logged in as someone else),
257
+ * this disconnects the wallet entirely -- it's a different identity.
258
+ */
259
+ async verifyAddressMatch() {
260
+ const keyContainer = await this.getSecureKey();
261
+ try {
262
+ const currentAddress = await keyContainer.useKey(async (secretKey) => {
263
+ const account = await deriveAlgorandAccountFromEd25519(secretKey);
264
+ const addr = account.addr;
265
+ zeroMemory(account.sk);
266
+ return addr;
267
+ });
268
+ if (currentAddress !== this._address) {
269
+ this.logger.warn("Re-authenticated as different user, disconnecting wallet", {
270
+ expected: this._address,
271
+ actual: currentAddress
272
+ });
273
+ this.onDisconnect();
274
+ throw new Error(`Re-authenticated as a different account. Expected ${this._address}, got ${currentAddress}. Please connect again with the correct account.`);
275
+ }
276
+ this.logger.info("Address verified, session restored");
277
+ } finally {
278
+ keyContainer.clear();
279
+ }
280
+ }
281
+ /**
282
+ * Connect to Web3Auth
283
+ *
284
+ * @param args - Optional connection arguments
285
+ * @param args.idToken - JWT token for custom authentication (e.g., Firebase ID token)
286
+ * @param args.verifierId - User identifier for custom authentication (e.g., email, uid)
287
+ * @param args.verifier - Custom verifier name (uses options.verifier if not provided)
288
+ *
289
+ * @example
290
+ * // Standard modal connection
291
+ * await wallet.connect()
292
+ *
293
+ * @example
294
+ * // Custom authentication with Firebase
295
+ * await wallet.connect({
296
+ * idToken: firebaseIdToken,
297
+ * verifierId: user.email,
298
+ * verifier: 'my-firebase-verifier'
299
+ * })
300
+ */
301
+ connect = async (args) => {
302
+ this.logger.info("Connecting to Web3Auth...");
303
+ try {
304
+ let provider;
305
+ const idToken = args?.idToken;
306
+ const verifierId = args?.verifierId;
307
+ const verifier = args?.verifier || this.options.verifier;
308
+ if (idToken && verifierId) {
309
+ if (!verifier) throw new Error("Custom authentication requires a verifier. Provide it in connect() args or options.verifier");
310
+ this.logger.info("Connecting with custom authentication (SFA)...", {
311
+ verifier,
312
+ verifierId
313
+ });
314
+ const web3authSFA = this.web3authSFA || await this.initializeSFAClient();
315
+ if (web3authSFA.connected) {
316
+ this.logger.debug("SFA already connected, logging out first...");
317
+ try {
318
+ await web3authSFA.logout();
319
+ } catch {}
320
+ }
321
+ provider = await web3authSFA.connect({
322
+ verifier,
323
+ verifierId,
324
+ idToken
325
+ });
326
+ this.usingSFA = true;
327
+ this.userInfo = { email: verifierId };
328
+ } else {
329
+ const web3auth = this.web3auth || await this.initializeClient();
330
+ provider = await web3auth.connect();
331
+ this.usingSFA = false;
332
+ this.userInfo = await web3auth.getUserInfo();
333
+ this.logger.debug("User info retrieved", { email: this.userInfo.email });
334
+ }
335
+ if (!provider) throw new Error("Failed to connect to Web3Auth");
336
+ const keyContainer = await this.getSecureKey();
337
+ try {
338
+ this._address = await keyContainer.useKey(async (secretKey) => {
339
+ const account = await deriveAlgorandAccountFromEd25519(secretKey);
340
+ const addr = account.addr;
341
+ zeroMemory(account.sk);
342
+ return addr;
343
+ });
344
+ } finally {
345
+ keyContainer.clear();
346
+ }
347
+ const walletAccount = {
348
+ name: this.userInfo.name || this.userInfo.email || `${this.metadata.name} Account`,
349
+ address: this._address
350
+ };
351
+ const walletState = {
352
+ accounts: [walletAccount],
353
+ activeAccount: walletAccount
354
+ };
355
+ this.store.addWallet(walletState);
356
+ this.saveMetadata();
357
+ this.logger.info("Connected successfully", { address: this._address });
358
+ return [walletAccount];
359
+ } catch (error) {
360
+ this.logger.error("Error connecting to Web3Auth:", error.message);
361
+ throw error;
362
+ }
363
+ };
364
+ /**
365
+ * Disconnect from Web3Auth
366
+ */
367
+ disconnect = async () => {
368
+ this.logger.info("Disconnecting from Web3Auth...");
369
+ try {
370
+ if (this.usingSFA && this.web3authSFA?.connected) await this.web3authSFA.logout();
371
+ else if (this.web3auth?.connected) await this.web3auth.logout();
372
+ } catch (error) {
373
+ this.logger.warn("Error during Web3Auth logout:", error.message);
374
+ }
375
+ this._address = null;
376
+ this.userInfo = null;
377
+ this.usingSFA = false;
378
+ this.clearMetadata();
379
+ this.onDisconnect();
380
+ this.logger.info("Disconnected");
381
+ };
382
+ /**
383
+ * Resume session from cached state
384
+ *
385
+ * LAZY AUTHENTICATION: We do NOT connect to Web3Auth here.
386
+ * We simply restore the cached address from localStorage.
387
+ * Web3Auth connection is deferred until signTransactions() is called.
388
+ */
389
+ resumeSession = async () => {
390
+ try {
391
+ const walletState = this.store.getWalletState();
392
+ if (!walletState) {
393
+ this.logger.info("No session to resume");
394
+ return;
395
+ }
396
+ const storedAccount = walletState.accounts[0];
397
+ if (!storedAccount?.address) {
398
+ this.logger.warn("No address found in cached session");
399
+ this.onDisconnect();
400
+ return;
401
+ }
402
+ this._address = storedAccount.address;
403
+ this.userInfo = { name: storedAccount.name };
404
+ const metadata = this.loadMetadata();
405
+ if (metadata) this.usingSFA = metadata.usingSFA;
406
+ this.logger.info("Session restored from cache (lazy mode)", { address: this._address });
407
+ } catch (error) {
408
+ this.logger.error("Error resuming session:", error.message);
409
+ this.onDisconnect();
410
+ throw error;
411
+ }
412
+ };
413
+ canUsePrivateKey = true;
414
+ /**
415
+ * Provide scoped access to the private key via a callback.
416
+ *
417
+ * The callback receives a 64-byte Algorand secret key (ed25519 seed + public key).
418
+ * The key is a fresh copy that is guaranteed to be zeroed from memory when the
419
+ * callback completes, whether it succeeds or throws.
420
+ *
421
+ * SECURITY: The key is fetched fresh from Web3Auth for each call and never cached.
422
+ *
423
+ * @example
424
+ * ```typescript
425
+ * const result = await wallet.withPrivateKey(async (secretKey) => {
426
+ * // secretKey is a 64-byte Uint8Array
427
+ * // Use for custom signing, authentication, etc.
428
+ * return doSomethingWith(secretKey)
429
+ * })
430
+ * // secretKey is zeroed at this point
431
+ * ```
432
+ */
433
+ withPrivateKey = async (callback) => {
434
+ this.logger.debug("withPrivateKey: Providing private key access...");
435
+ await this.ensureConnected();
436
+ const keyContainer = await this.getSecureKey();
437
+ try {
438
+ return await keyContainer.useKey(async (secretKey) => {
439
+ const account = await deriveAlgorandAccountFromEd25519(secretKey);
440
+ const skCopy = new Uint8Array(account.sk);
441
+ zeroMemory(account.sk);
442
+ try {
443
+ return await callback(skCopy);
444
+ } finally {
445
+ zeroMemory(skCopy);
446
+ }
447
+ });
448
+ } finally {
449
+ keyContainer.clear();
450
+ }
451
+ };
452
+ /**
453
+ * Process transactions for signing
454
+ */
455
+ processTxns(txnGroup, indexesToSign) {
456
+ const txnsToSign = [];
457
+ txnGroup.forEach((txn, index) => {
458
+ const isIndexMatch = !indexesToSign || indexesToSign.includes(index);
459
+ const canSignTxn = txn.sender.toString() === this._address;
460
+ if (isIndexMatch && canSignTxn) txnsToSign.push(txn);
461
+ });
462
+ return txnsToSign;
463
+ }
464
+ /**
465
+ * Process encoded transactions for signing
466
+ */
467
+ processEncodedTxns(txnGroup, indexesToSign) {
468
+ const txnsToSign = [];
469
+ txnGroup.forEach((txnBuffer, index) => {
470
+ const isSigned = isSignedTxn(algosdk.msgpackRawDecode(txnBuffer));
471
+ const txn = isSigned ? algosdk.decodeSignedTransaction(txnBuffer).txn : algosdk.decodeUnsignedTransaction(txnBuffer);
472
+ const isIndexMatch = !indexesToSign || indexesToSign.includes(index);
473
+ const signer = txn.sender.toString();
474
+ const canSignTxn = !isSigned && signer === this._address;
475
+ if (isIndexMatch && canSignTxn) txnsToSign.push(txn);
476
+ });
477
+ return txnsToSign;
478
+ }
479
+ /**
480
+ * Sign transactions
481
+ *
482
+ * LAZY AUTHENTICATION: If the Web3Auth session has expired, this will
483
+ * automatically re-authenticate before signing.
484
+ *
485
+ * SECURITY: The private key is fetched fresh, used for signing,
486
+ * and immediately cleared from memory. The key is never stored
487
+ * between signing operations.
488
+ */
489
+ signTransactions = async (txnGroup, indexesToSign) => {
490
+ try {
491
+ this.logger.debug("Signing transactions...", {
492
+ txnGroup,
493
+ indexesToSign
494
+ });
495
+ await this.ensureConnected();
496
+ let txnsToSign = [];
497
+ if (isTransactionArray(txnGroup)) {
498
+ const flatTxns = flattenTxnGroup(txnGroup);
499
+ txnsToSign = this.processTxns(flatTxns, indexesToSign);
500
+ } else {
501
+ const flatTxns = flattenTxnGroup(txnGroup);
502
+ txnsToSign = this.processEncodedTxns(flatTxns, indexesToSign);
503
+ }
504
+ if (txnsToSign.length === 0) {
505
+ this.logger.debug("No transactions to sign");
506
+ return [];
507
+ }
508
+ const keyContainer = await this.getSecureKey();
509
+ let signedTxns = [];
510
+ try {
511
+ signedTxns = await keyContainer.useKey(async (secretKey) => {
512
+ const account = await deriveAlgorandAccountFromEd25519(secretKey);
513
+ try {
514
+ return txnsToSign.map((txn) => txn.signTxn(account.sk));
515
+ } finally {
516
+ zeroMemory(account.sk);
517
+ }
518
+ });
519
+ } finally {
520
+ keyContainer.clear();
521
+ }
522
+ this.logger.debug("Transactions signed successfully", { count: signedTxns.length });
523
+ return signedTxns;
524
+ } catch (error) {
525
+ this.logger.error("Error signing transactions:", error.message);
526
+ throw error;
527
+ }
528
+ };
529
+ };
530
+ //#endregion
531
+ //#region src/index.ts
532
+ const WALLET_ID = "web3auth";
533
+ function web3auth(options) {
534
+ return {
535
+ id: WALLET_ID,
536
+ metadata: Web3AuthAdapter.defaultMetadata,
537
+ Adapter: Web3AuthAdapter,
538
+ options,
539
+ capabilities: { supportedNetworks: ["mainnet"] }
540
+ };
541
+ }
542
+ //#endregion
543
+ export { WALLET_ID, Web3AuthAdapter, web3auth };
544
+
545
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/icon.ts","../src/adapter.ts","../src/index.ts"],"sourcesContent":["export const icon = `\n<svg viewBox=\"0 0 40 40\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect fill=\"#0364FF\" width=\"40\" height=\"40\" rx=\"8\"/>\n <path fill=\"#FFFFFF\" d=\"M20 8c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12S26.627 8 20 8zm0 21.6c-5.302 0-9.6-4.298-9.6-9.6S14.698 10.4 20 10.4s9.6 4.298 9.6 9.6-4.298 9.6-9.6 9.6zm0-16.8c-3.976 0-7.2 3.224-7.2 7.2s3.224 7.2 7.2 7.2 7.2-3.224 7.2-7.2-3.224-7.2-7.2-7.2zm0 12c-2.651 0-4.8-2.149-4.8-4.8s2.149-4.8 4.8-4.8 4.8 2.149 4.8 4.8-2.149 4.8-4.8 4.8z\"/>\n</svg>\n`\n","/**\n * Web3Auth Wallet Adapter for Algorand\n *\n * SECURITY CONSIDERATIONS:\n * - Web3Auth exposes the raw private key for non-EVM chains like Algorand\n * - This implementation uses SecureKeyContainer to minimize key exposure\n * - Keys are never persisted to localStorage or any storage\n * - Keys are cleared from memory immediately after signing operations\n * - Session resumption requires re-authentication (keys are not cached)\n *\n * @see https://web3auth.io/docs\n */\n\nimport algosdk from 'algosdk'\nimport {\n BaseWallet,\n SecureKeyContainer,\n zeroMemory,\n deriveAlgorandAccountFromEd25519,\n flattenTxnGroup,\n isSignedTxn,\n isTransactionArray,\n type AdapterConstructorParams,\n type WalletAccount,\n type WalletMetadata,\n type WalletState\n} from '@txnlab/use-wallet/adapter'\n\nconst LOCAL_STORAGE_WEB3AUTH_KEY = '@txnlab/use-wallet:v5:web3auth'\n\n/** Metadata persisted to localStorage for Web3Auth session restoration */\ninterface Web3AuthMetadata {\n /** Whether the session was established using Single Factor Auth (SFA) vs modal */\n usingSFA: boolean\n}\n\n// Type definitions for Web3Auth (to avoid requiring the package at compile time)\n// These are minimal type definitions that match the actual Web3Auth API\ninterface IWeb3AuthProvider {\n request<T>(args: { method: string; params?: unknown }): Promise<T>\n}\n\ninterface IWeb3AuthUserInfo {\n email?: string\n name?: string\n profileImage?: string\n verifier?: string\n verifierId?: string\n typeOfLogin?: string\n aggregateVerifier?: string\n}\n\ninterface IWeb3AuthModal {\n init(): Promise<void>\n connect(): Promise<IWeb3AuthProvider | null>\n logout(): Promise<void>\n connected: boolean\n provider: IWeb3AuthProvider | null\n getUserInfo(): Promise<Partial<IWeb3AuthUserInfo>>\n}\n\n// Single Factor Auth SDK interface (for custom JWT auth)\ninterface IWeb3AuthSFA {\n init(): Promise<void>\n connect(params: {\n verifier: string\n verifierId: string\n idToken: string\n }): Promise<IWeb3AuthProvider | null>\n logout(): Promise<void>\n connected: boolean\n provider: IWeb3AuthProvider | null\n}\n\n/**\n * Parameters for custom authentication (e.g., Firebase, custom JWT)\n */\nexport interface Web3AuthCustomAuth {\n /**\n * Custom verifier name configured in Web3Auth dashboard\n */\n verifier: string\n\n /**\n * User identifier (e.g., email, Firebase UID)\n */\n verifierId: string\n\n /**\n * JWT token from your authentication provider (e.g., Firebase ID token)\n */\n idToken: string\n}\n\n/**\n * Credentials returned by getAuthCredentials callback\n */\nexport interface Web3AuthCredentials {\n /**\n * JWT token from your authentication provider (e.g., Firebase ID token)\n */\n idToken: string\n\n /**\n * User identifier (e.g., email, Firebase UID)\n */\n verifierId: string\n\n /**\n * Custom verifier name (optional, uses options.verifier if not provided)\n */\n verifier?: string\n}\n\n/**\n * Web3Auth configuration options\n */\nexport interface Web3AuthOptions {\n /**\n * Web3Auth Client ID from the dashboard\n * @see https://dashboard.web3auth.io\n */\n clientId: string\n\n /**\n * Web3Auth network (mainnet, testnet, sapphire_mainnet, sapphire_devnet, cyan, aqua)\n * @default 'sapphire_mainnet'\n */\n web3AuthNetwork?: 'mainnet' | 'testnet' | 'sapphire_mainnet' | 'sapphire_devnet' | 'cyan' | 'aqua'\n\n /**\n * Login provider to use (google, facebook, twitter, discord, etc.)\n * If not specified, the Web3Auth modal will be shown\n */\n loginProvider?:\n | 'google'\n | 'facebook'\n | 'twitter'\n | 'discord'\n | 'reddit'\n | 'twitch'\n | 'apple'\n | 'line'\n | 'github'\n | 'kakao'\n | 'linkedin'\n | 'weibo'\n | 'wechat'\n | 'email_passwordless'\n | 'sms_passwordless'\n\n /**\n * Login hint for email_passwordless or sms_passwordless\n */\n loginHint?: string\n\n /**\n * UI configuration for the Web3Auth modal\n */\n uiConfig?: {\n appName?: string\n appUrl?: string\n logoLight?: string\n logoDark?: string\n defaultLanguage?: string\n mode?: 'light' | 'dark' | 'auto'\n theme?: Record<string, string>\n }\n\n /**\n * Whether to use the popup flow instead of redirect\n * @default true\n */\n usePopup?: boolean\n\n /**\n * Default verifier name for custom authentication.\n * When set, connect() can be called with just { idToken, verifierId }\n */\n verifier?: string\n\n /**\n * Callback to get fresh authentication credentials when session expires.\n * Required for automatic re-authentication with Single Factor Auth (SFA).\n *\n * If not provided and the session expires, signTransactions() will throw\n * an error requiring the user to call connect() with fresh credentials.\n *\n * @example\n * ```typescript\n * getAuthCredentials: async () => {\n * const user = firebase.auth().currentUser\n * if (!user) throw new Error('Not logged in')\n * const idToken = await user.getIdToken(true)\n * return { idToken, verifierId: user.email || user.uid }\n * }\n * ```\n */\n getAuthCredentials?: () => Promise<Web3AuthCredentials>\n}\n\nimport { icon } from './icon'\n\nconst ICON = `data:image/svg+xml;base64,${btoa(icon)}`\n\nexport class Web3AuthAdapter extends BaseWallet<Web3AuthOptions> {\n private web3auth: IWeb3AuthModal | null = null\n private web3authSFA: IWeb3AuthSFA | null = null\n private userInfo: Partial<IWeb3AuthUserInfo> | null = null\n\n /**\n * SECURITY: We store only the address, NEVER the private key.\n * Keys are fetched fresh from Web3Auth and immediately cleared after use.\n */\n private _address: string | null = null\n\n /** Track which SDK is currently in use */\n private usingSFA: boolean = false\n\n constructor(params: AdapterConstructorParams<Web3AuthOptions>) {\n super(params)\n\n if (!params.options?.clientId) {\n this.logger.error('Missing required option: clientId')\n throw new Error('Missing required option: clientId')\n }\n\n // Apply defaults\n this.options = {\n web3AuthNetwork: 'sapphire_mainnet',\n usePopup: true,\n ...params.options\n }\n }\n\n static defaultMetadata: WalletMetadata = {\n name: 'Web3Auth',\n icon: ICON\n }\n\n // ---------- Metadata Persistence ----------------------------------- //\n\n private loadMetadata(): Web3AuthMetadata | null {\n if (typeof localStorage === 'undefined') return null\n const data = localStorage.getItem(LOCAL_STORAGE_WEB3AUTH_KEY)\n if (!data) return null\n try {\n return JSON.parse(data) as Web3AuthMetadata\n } catch {\n return null\n }\n }\n\n private saveMetadata(): void {\n if (typeof localStorage === 'undefined') return\n const metadata: Web3AuthMetadata = { usingSFA: this.usingSFA }\n localStorage.setItem(LOCAL_STORAGE_WEB3AUTH_KEY, JSON.stringify(metadata))\n }\n\n private clearMetadata(): void {\n if (typeof localStorage === 'undefined') return\n localStorage.removeItem(LOCAL_STORAGE_WEB3AUTH_KEY)\n }\n\n // ---------- Client Initialization ---------------------------------- //\n\n /**\n * Initialize the Web3Auth client (v10 Modal SDK)\n */\n private async initializeClient(): Promise<IWeb3AuthModal> {\n this.logger.info('Initializing Web3Auth client...')\n\n let Web3Auth: any\n\n let WEB3AUTH_NETWORK: any\n\n try {\n // Dynamic import - @web3auth/modal is a dependency\n const modal = await import('@web3auth/modal')\n Web3Auth = modal.Web3Auth\n WEB3AUTH_NETWORK = modal.WEB3AUTH_NETWORK\n } catch (error) {\n this.logger.error('Failed to load Web3Auth.', error)\n throw new Error('Web3Auth package not found. Please install @web3auth/modal')\n }\n\n const networkMap: Record<string, string> = {\n mainnet: WEB3AUTH_NETWORK.MAINNET,\n testnet: WEB3AUTH_NETWORK.TESTNET,\n sapphire_mainnet: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,\n sapphire_devnet: WEB3AUTH_NETWORK.SAPPHIRE_DEVNET,\n cyan: WEB3AUTH_NETWORK.CYAN,\n aqua: WEB3AUTH_NETWORK.AQUA\n }\n\n // v10: Chain config and provider are handled internally for non-EVM chains.\n // Only clientId, web3AuthNetwork, and uiConfig are needed.\n const web3auth = new Web3Auth({\n clientId: this.options.clientId,\n web3AuthNetwork: networkMap[this.options.web3AuthNetwork || 'sapphire_mainnet'] as any,\n uiConfig: this.options.uiConfig\n })\n\n await web3auth.init()\n this.web3auth = web3auth\n this.logger.info('Web3Auth client initialized')\n\n return web3auth\n }\n\n /**\n * Initialize the Web3Auth Single Factor Auth client for custom JWT authentication.\n * SFA SDK is still at v9 and requires CommonPrivateKeyProvider with chain config.\n */\n private async initializeSFAClient(): Promise<IWeb3AuthSFA> {\n this.logger.info('Initializing Web3Auth Single Factor Auth client...')\n\n let Web3Auth: any\n\n let WEB3AUTH_NETWORK: any\n\n let CommonPrivateKeyProvider: any\n\n try {\n // Dynamic imports\n const sfa = await import('@web3auth/single-factor-auth')\n Web3Auth = sfa.Web3Auth\n // Import WEB3AUTH_NETWORK from @web3auth/modal (v10 re-exports it)\n const modal = await import('@web3auth/modal')\n WEB3AUTH_NETWORK = modal.WEB3AUTH_NETWORK\n const baseProvider = await import('@web3auth/base-provider')\n CommonPrivateKeyProvider = baseProvider.CommonPrivateKeyProvider\n } catch {\n this.logger.error(\n 'Failed to load Web3Auth SFA. Make sure @web3auth/single-factor-auth ' +\n 'and @web3auth/base-provider are installed.'\n )\n throw new Error(\n 'Web3Auth SFA packages not found. Please install @web3auth/single-factor-auth ' +\n 'and @web3auth/base-provider'\n )\n }\n\n const chainConfig = {\n chainNamespace: 'other',\n chainId: 'algorand',\n rpcTarget: 'https://mainnet-api.algonode.cloud',\n displayName: 'Algorand',\n blockExplorerUrl: 'https://lora.algokit.io/mainnet',\n ticker: 'ALGO',\n tickerName: 'Algorand'\n }\n\n const networkMap: Record<string, string> = {\n mainnet: WEB3AUTH_NETWORK.MAINNET,\n testnet: WEB3AUTH_NETWORK.TESTNET,\n sapphire_mainnet: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,\n sapphire_devnet: WEB3AUTH_NETWORK.SAPPHIRE_DEVNET,\n cyan: WEB3AUTH_NETWORK.CYAN,\n aqua: WEB3AUTH_NETWORK.AQUA\n }\n\n // SFA v9 still requires CommonPrivateKeyProvider for non-EVM chains\n const privateKeyProvider = new CommonPrivateKeyProvider({\n config: { chainConfig }\n })\n\n const web3authSFA = new Web3Auth({\n clientId: this.options.clientId,\n web3AuthNetwork: networkMap[this.options.web3AuthNetwork || 'sapphire_mainnet'] as any,\n privateKeyProvider\n })\n\n await web3authSFA.init()\n this.web3authSFA = web3authSFA\n this.logger.info('Web3Auth SFA client initialized')\n\n return web3authSFA\n }\n\n // ---------- Secure Key Handling ------------------------------------ //\n\n /**\n * SECURITY: Fetch the private key from Web3Auth and return it in a SecureKeyContainer.\n * The caller MUST call container.clear() when done.\n *\n * @returns SecureKeyContainer holding the private key\n */\n private async getSecureKey(): Promise<SecureKeyContainer> {\n // Get the provider from either the modal SDK or SFA SDK\n const provider = this.usingSFA ? this.web3authSFA?.provider : this.web3auth?.provider\n\n if (!provider) {\n throw new Error('Web3Auth not connected')\n }\n\n this.logger.debug('Fetching private key from Web3Auth...')\n\n // Request the private key from Web3Auth\n // For non-EVM chains, Web3Auth returns the raw ed25519 private key\n const privateKeyHex = await provider.request<string>({\n method: 'private_key'\n })\n\n if (!privateKeyHex || typeof privateKeyHex !== 'string') {\n throw new Error('Failed to retrieve private key from Web3Auth')\n }\n\n // Convert hex string to Uint8Array\n const privateKeyBytes = this.hexToBytes(privateKeyHex)\n\n // SECURITY: Immediately clear the hex string from our scope\n // (The original string may still exist in Web3Auth's scope)\n\n // Wrap in SecureKeyContainer for safe handling\n const container = new SecureKeyContainer(privateKeyBytes)\n\n // SECURITY: Zero the local copy now that it's in the container\n zeroMemory(privateKeyBytes)\n\n this.logger.debug('Private key retrieved and secured')\n return container\n }\n\n /**\n * Convert a hex string to Uint8Array\n */\n private hexToBytes(hex: string): Uint8Array {\n // Remove 0x prefix if present\n const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex\n const bytes = new Uint8Array(cleanHex.length / 2)\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16)\n }\n return bytes\n }\n\n // ---------- Session Management ------------------------------------- //\n\n /**\n * Check if Web3Auth is currently connected with a valid session\n */\n private isWeb3AuthConnected(): boolean {\n if (this.usingSFA) {\n return Boolean(this.web3authSFA?.connected && this.web3authSFA?.provider)\n }\n return Boolean(this.web3auth?.connected && this.web3auth?.provider)\n }\n\n /**\n * Ensure Web3Auth is connected and ready for signing.\n * Re-authenticates if the session has expired.\n *\n * This is called lazily when signTransactions() is invoked.\n */\n private async ensureConnected(): Promise<void> {\n if (this.isWeb3AuthConnected()) {\n this.logger.debug('Web3Auth session still valid')\n return\n }\n\n this.logger.info('Web3Auth session expired or not initialized, re-authenticating...')\n\n if (this.usingSFA) {\n await this.reconnectSFA()\n } else {\n await this.reconnectModal()\n }\n }\n\n /**\n * Re-authenticate using Single Factor Auth (Firebase, custom JWT)\n *\n * Requires getAuthCredentials callback to be configured in options.\n * If the callback returns credentials for a different user, this will\n * disconnect the current wallet (the user logged out and back in as someone else).\n */\n private async reconnectSFA(): Promise<void> {\n if (!this.options.getAuthCredentials) {\n this.logger.error('Cannot re-authenticate: getAuthCredentials callback not configured')\n throw new Error(\n 'Web3Auth session expired. Configure getAuthCredentials option for automatic re-auth, ' +\n 'or call disconnect() and connect() with fresh credentials.'\n )\n }\n\n this.logger.info('Getting fresh credentials for SFA re-authentication...')\n\n let credentials: Web3AuthCredentials\n try {\n credentials = await this.options.getAuthCredentials()\n } catch (error: any) {\n // User is no longer authenticated with the identity provider (e.g., logged out of Firebase)\n this.logger.warn('Failed to get auth credentials, user may have logged out:', error.message)\n this.onDisconnect()\n throw new Error('Authentication provider session expired. Please log in again.')\n }\n\n // Initialize SFA client if needed\n const web3authSFA = this.web3authSFA || (await this.initializeSFAClient())\n\n // Logout first if still connected (stale session)\n if (web3authSFA.connected) {\n try {\n await web3authSFA.logout()\n } catch {\n // Ignore logout errors\n }\n }\n\n const verifier = credentials.verifier || this.options.verifier\n if (!verifier) {\n throw new Error('No verifier configured for SFA authentication')\n }\n\n // Connect with fresh credentials\n const provider = await web3authSFA.connect({\n verifier,\n verifierId: credentials.verifierId,\n idToken: credentials.idToken\n })\n\n if (!provider) {\n throw new Error('Failed to re-authenticate with Web3Auth SFA')\n }\n\n this.usingSFA = true\n this.saveMetadata()\n\n // Verify we got the same address (same user)\n await this.verifyAddressMatch()\n }\n\n /**\n * Re-authenticate using the Web3Auth modal\n *\n * Shows the Web3Auth login modal for the user to authenticate again.\n * If they log in as a different user, this will disconnect the current wallet.\n */\n private async reconnectModal(): Promise<void> {\n this.logger.info('Showing Web3Auth modal for re-authentication...')\n\n const web3auth = this.web3auth || (await this.initializeClient())\n\n // Logout first if still connected (stale session)\n if (web3auth.connected) {\n try {\n await web3auth.logout()\n } catch {\n // Ignore logout errors\n }\n }\n\n const provider = await web3auth.connect()\n\n if (!provider) {\n throw new Error('Re-authentication cancelled or failed')\n }\n\n this.usingSFA = false\n this.saveMetadata()\n\n // Get updated user info\n this.userInfo = await web3auth.getUserInfo()\n\n // Verify we got the same address (same user)\n await this.verifyAddressMatch()\n }\n\n /**\n * Verify that the current Web3Auth session matches the cached address.\n *\n * If the address doesn't match (user logged in as someone else),\n * this disconnects the wallet entirely -- it's a different identity.\n */\n private async verifyAddressMatch(): Promise<void> {\n const keyContainer = await this.getSecureKey()\n\n try {\n const currentAddress = await keyContainer.useKey(async (secretKey) => {\n const account = await deriveAlgorandAccountFromEd25519(secretKey)\n const addr = account.addr\n zeroMemory(account.sk)\n return addr\n })\n\n if (currentAddress !== this._address) {\n this.logger.warn('Re-authenticated as different user, disconnecting wallet', {\n expected: this._address,\n actual: currentAddress\n })\n\n // Different user = different wallet. Full disconnect required.\n this.onDisconnect()\n\n throw new Error(\n `Re-authenticated as a different account. Expected ${this._address}, ` +\n `got ${currentAddress}. Please connect again with the correct account.`\n )\n }\n\n this.logger.info('Address verified, session restored')\n } finally {\n keyContainer.clear()\n }\n }\n\n // ---------- Public Methods ----------------------------------------- //\n\n /**\n * Connect to Web3Auth\n *\n * @param args - Optional connection arguments\n * @param args.idToken - JWT token for custom authentication (e.g., Firebase ID token)\n * @param args.verifierId - User identifier for custom authentication (e.g., email, uid)\n * @param args.verifier - Custom verifier name (uses options.verifier if not provided)\n *\n * @example\n * // Standard modal connection\n * await wallet.connect()\n *\n * @example\n * // Custom authentication with Firebase\n * await wallet.connect({\n * idToken: firebaseIdToken,\n * verifierId: user.email,\n * verifier: 'my-firebase-verifier'\n * })\n */\n public connect = async (args?: Record<string, any>): Promise<WalletAccount[]> => {\n this.logger.info('Connecting to Web3Auth...')\n\n try {\n let provider: IWeb3AuthProvider | null\n\n // Check if custom authentication params are provided\n const idToken = args?.idToken as string | undefined\n const verifierId = args?.verifierId as string | undefined\n const verifier = (args?.verifier as string | undefined) || this.options.verifier\n\n if (idToken && verifierId) {\n // Custom authentication flow using Single Factor Auth (e.g., Firebase)\n if (!verifier) {\n throw new Error(\n 'Custom authentication requires a verifier. Provide it in connect() args or options.verifier'\n )\n }\n\n this.logger.info('Connecting with custom authentication (SFA)...', {\n verifier,\n verifierId\n })\n\n // Initialize the SFA client\n const web3authSFA = this.web3authSFA || (await this.initializeSFAClient())\n\n // If already connected, logout first to allow reconnection with potentially different credentials\n if (web3authSFA.connected) {\n this.logger.debug('SFA already connected, logging out first...')\n try {\n await web3authSFA.logout()\n } catch {\n // Ignore logout errors\n }\n }\n\n // Connect using Single Factor Auth - no modal, direct connection\n provider = await web3authSFA.connect({\n verifier,\n verifierId,\n idToken\n })\n\n this.usingSFA = true\n\n // SFA doesn't provide getUserInfo, use verifierId as display name\n this.userInfo = { email: verifierId }\n } else {\n // Standard modal connection\n const web3auth = this.web3auth || (await this.initializeClient())\n provider = await web3auth.connect()\n\n this.usingSFA = false\n\n // Get user info for display purposes (modal SDK only)\n this.userInfo = await web3auth.getUserInfo()\n this.logger.debug('User info retrieved', {\n email: this.userInfo.email\n })\n }\n\n if (!provider) {\n throw new Error('Failed to connect to Web3Auth')\n }\n\n // SECURITY: Get the key, derive the address, and immediately clear the key\n const keyContainer = await this.getSecureKey()\n\n try {\n const address = await keyContainer.useKey(async (secretKey) => {\n const account = await deriveAlgorandAccountFromEd25519(secretKey)\n // SECURITY: Zero the derived account's secret key immediately\n const addr = account.addr\n zeroMemory(account.sk)\n return addr\n })\n\n this._address = address\n } finally {\n // SECURITY: Always clear the key container\n keyContainer.clear()\n }\n\n const walletAccount: WalletAccount = {\n name: this.userInfo.name || this.userInfo.email || `${this.metadata.name} Account`,\n address: this._address\n }\n\n const walletState: WalletState = {\n accounts: [walletAccount],\n activeAccount: walletAccount\n }\n\n this.store.addWallet(walletState)\n\n // Save metadata only after successful connection\n this.saveMetadata()\n\n this.logger.info('Connected successfully', { address: this._address })\n return [walletAccount]\n } catch (error: any) {\n this.logger.error('Error connecting to Web3Auth:', error.message)\n throw error\n }\n }\n\n /**\n * Disconnect from Web3Auth\n */\n public disconnect = async (): Promise<void> => {\n this.logger.info('Disconnecting from Web3Auth...')\n\n try {\n if (this.usingSFA && this.web3authSFA?.connected) {\n await this.web3authSFA.logout()\n } else if (this.web3auth?.connected) {\n await this.web3auth.logout()\n }\n } catch (error: any) {\n this.logger.warn('Error during Web3Auth logout:', error.message)\n }\n\n // Clear local state\n this._address = null\n this.userInfo = null\n this.usingSFA = false\n this.clearMetadata()\n this.onDisconnect()\n\n this.logger.info('Disconnected')\n }\n\n /**\n * Resume session from cached state\n *\n * LAZY AUTHENTICATION: We do NOT connect to Web3Auth here.\n * We simply restore the cached address from localStorage.\n * Web3Auth connection is deferred until signTransactions() is called.\n */\n public resumeSession = async (): Promise<void> => {\n try {\n const walletState = this.store.getWalletState()\n\n if (!walletState) {\n this.logger.info('No session to resume')\n return\n }\n\n const storedAccount = walletState.accounts[0]\n\n if (!storedAccount?.address) {\n this.logger.warn('No address found in cached session')\n this.onDisconnect()\n return\n }\n\n // Just restore the cached address - don't initialize Web3Auth\n this._address = storedAccount.address\n this.userInfo = { name: storedAccount.name }\n\n // Restore usingSFA flag from metadata\n const metadata = this.loadMetadata()\n if (metadata) {\n this.usingSFA = metadata.usingSFA\n }\n\n this.logger.info('Session restored from cache (lazy mode)', {\n address: this._address\n })\n } catch (error: any) {\n this.logger.error('Error resuming session:', error.message)\n this.onDisconnect()\n throw error\n }\n }\n\n // ---------- Private Key Access ------------------------------------- //\n\n public canUsePrivateKey = true\n\n /**\n * Provide scoped access to the private key via a callback.\n *\n * The callback receives a 64-byte Algorand secret key (ed25519 seed + public key).\n * The key is a fresh copy that is guaranteed to be zeroed from memory when the\n * callback completes, whether it succeeds or throws.\n *\n * SECURITY: The key is fetched fresh from Web3Auth for each call and never cached.\n *\n * @example\n * ```typescript\n * const result = await wallet.withPrivateKey(async (secretKey) => {\n * // secretKey is a 64-byte Uint8Array\n * // Use for custom signing, authentication, etc.\n * return doSomethingWith(secretKey)\n * })\n * // secretKey is zeroed at this point\n * ```\n */\n public withPrivateKey = async <T>(\n callback: (secretKey: Uint8Array) => Promise<T>\n ): Promise<T> => {\n this.logger.debug('withPrivateKey: Providing private key access...')\n\n // Ensure Web3Auth is connected (re-authenticates if session expired)\n await this.ensureConnected()\n\n // SECURITY: Fetch key, derive Algorand account, provide copy to consumer\n const keyContainer = await this.getSecureKey()\n\n try {\n return await keyContainer.useKey(async (secretKey) => {\n const account = await deriveAlgorandAccountFromEd25519(secretKey)\n\n // Create a copy for the consumer\n const skCopy = new Uint8Array(account.sk)\n\n // SECURITY: Zero the derived account's secret key immediately\n zeroMemory(account.sk)\n\n try {\n return await callback(skCopy)\n } finally {\n // SECURITY: Always zero the consumer's copy\n zeroMemory(skCopy)\n }\n })\n } finally {\n // SECURITY: Always clear the key container\n keyContainer.clear()\n }\n }\n\n // ---------- Transaction Signing ------------------------------------ //\n\n /**\n * Process transactions for signing\n */\n private processTxns(\n txnGroup: algosdk.Transaction[],\n indexesToSign?: number[]\n ): algosdk.Transaction[] {\n const txnsToSign: algosdk.Transaction[] = []\n\n txnGroup.forEach((txn, index) => {\n const isIndexMatch = !indexesToSign || indexesToSign.includes(index)\n const signer = txn.sender.toString()\n const canSignTxn = signer === this._address\n\n if (isIndexMatch && canSignTxn) {\n txnsToSign.push(txn)\n }\n })\n\n return txnsToSign\n }\n\n /**\n * Process encoded transactions for signing\n */\n private processEncodedTxns(\n txnGroup: Uint8Array[],\n indexesToSign?: number[]\n ): algosdk.Transaction[] {\n const txnsToSign: algosdk.Transaction[] = []\n\n txnGroup.forEach((txnBuffer, index) => {\n const decodedObj = algosdk.msgpackRawDecode(txnBuffer)\n const isSigned = isSignedTxn(decodedObj)\n\n const txn: algosdk.Transaction = isSigned\n ? algosdk.decodeSignedTransaction(txnBuffer).txn\n : algosdk.decodeUnsignedTransaction(txnBuffer)\n\n const isIndexMatch = !indexesToSign || indexesToSign.includes(index)\n const signer = txn.sender.toString()\n const canSignTxn = !isSigned && signer === this._address\n\n if (isIndexMatch && canSignTxn) {\n txnsToSign.push(txn)\n }\n })\n\n return txnsToSign\n }\n\n /**\n * Sign transactions\n *\n * LAZY AUTHENTICATION: If the Web3Auth session has expired, this will\n * automatically re-authenticate before signing.\n *\n * SECURITY: The private key is fetched fresh, used for signing,\n * and immediately cleared from memory. The key is never stored\n * between signing operations.\n */\n public signTransactions = async <T extends algosdk.Transaction[] | Uint8Array[]>(\n txnGroup: T | T[],\n indexesToSign?: number[]\n ): Promise<(Uint8Array | null)[]> => {\n try {\n this.logger.debug('Signing transactions...', {\n txnGroup,\n indexesToSign\n })\n\n // Ensure Web3Auth is connected (re-authenticates if session expired)\n await this.ensureConnected()\n\n let txnsToSign: algosdk.Transaction[] = []\n\n // Determine type and process transactions for signing\n if (isTransactionArray(txnGroup)) {\n const flatTxns: algosdk.Transaction[] = flattenTxnGroup(txnGroup)\n txnsToSign = this.processTxns(flatTxns, indexesToSign)\n } else {\n const flatTxns: Uint8Array[] = flattenTxnGroup(txnGroup as Uint8Array[])\n txnsToSign = this.processEncodedTxns(flatTxns, indexesToSign)\n }\n\n if (txnsToSign.length === 0) {\n this.logger.debug('No transactions to sign')\n return []\n }\n\n // SECURITY: Fetch key, sign, and immediately clear\n const keyContainer = await this.getSecureKey()\n let signedTxns: Uint8Array[] = []\n\n try {\n signedTxns = await keyContainer.useKey(async (secretKey) => {\n const account = await deriveAlgorandAccountFromEd25519(secretKey)\n\n try {\n // Sign all transactions\n const signed = txnsToSign.map((txn) => txn.signTxn(account.sk))\n return signed\n } finally {\n // SECURITY: Always zero the account's secret key\n zeroMemory(account.sk)\n }\n })\n } finally {\n // SECURITY: Always clear the key container\n keyContainer.clear()\n }\n\n this.logger.debug('Transactions signed successfully', {\n count: signedTxns.length\n })\n return signedTxns\n } catch (error: any) {\n this.logger.error('Error signing transactions:', error.message)\n throw error\n }\n }\n}\n","import { Web3AuthAdapter } from './adapter'\nimport type { Web3AuthOptions } from './adapter'\nimport type { WalletAdapterConfig } from '@txnlab/use-wallet'\n\nexport const WALLET_ID = 'web3auth' as const\n\nexport function web3auth(options: Web3AuthOptions): WalletAdapterConfig {\n return {\n id: WALLET_ID,\n metadata: Web3AuthAdapter.defaultMetadata,\n Adapter: Web3AuthAdapter as unknown as WalletAdapterConfig['Adapter'],\n options: options as unknown as Record<string, unknown>,\n capabilities: { supportedNetworks: ['mainnet'] }\n }\n}\n\nexport { Web3AuthAdapter }\nexport type { Web3AuthOptions, Web3AuthCustomAuth, Web3AuthCredentials } from './adapter'\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@txnlab/use-wallet-web3auth",
3
+ "version": "5.0.0-rc.1",
4
+ "publishConfig": {
5
+ "access": "public",
6
+ "provenance": true
7
+ },
8
+ "description": "Web3Auth wallet adapter for @txnlab/use-wallet",
9
+ "author": "Doug Richar <drichar@gmail.com>",
10
+ "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/txnlab/use-wallet.git",
14
+ "directory": "packages/wallets/web3auth"
15
+ },
16
+ "type": "module",
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "peerDependencies": {
29
+ "@txnlab/use-wallet": "^5.0.0",
30
+ "algosdk": "^3.0.0"
31
+ },
32
+ "dependencies": {
33
+ "@web3auth/base-provider": "9.7.0",
34
+ "@web3auth/modal": "10.15.0",
35
+ "@web3auth/single-factor-auth": "9.5.0"
36
+ },
37
+ "devDependencies": {
38
+ "@txnlab/use-wallet": "5.0.0-rc.1",
39
+ "algosdk": "3.5.2",
40
+ "tsdown": "0.21.0",
41
+ "typescript": "5.9.3"
42
+ },
43
+ "scripts": {
44
+ "build": "tsdown",
45
+ "start": "tsdown --watch",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest --watch",
48
+ "lint": "eslint \"src/**/*.{js,ts}\"",
49
+ "typecheck": "tsc --noEmit"
50
+ }
51
+ }