Skip to content

Commit 42e0ebf

Browse files
authored
fix(rn-signer): switch back to session stamper after using passkey (#2147)
Fixes a state management bug in which once the react native signer client switched to the passkey stamper, it could never switch back to the session stamper. The new logic is made to look very similar to that of the web signer client.
1 parent 923d298 commit 42e0ebf

File tree

1 file changed

+35
-14
lines changed

1 file changed

+35
-14
lines changed

account-kit/rn-signer/src/client.ts

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ export type ExportWalletParams = {
6161

6262
export type ExportWalletResult = string;
6363

64+
const SESSION_STAMPER = NativeTEKStamper;
65+
6466
// TODO: need to emit events
6567
export class RNSignerClient extends BaseSignerClient<
6668
ExportWalletParams,
6769
string
6870
> {
69-
private stamper = NativeTEKStamper;
7071
oauthCallbackUrl: string;
7172
rpId: string | undefined;
7273
private validAuthenticatingTypes: AuthenticatingEventMetadata["type"][] = [
@@ -80,7 +81,7 @@ export class RNSignerClient extends BaseSignerClient<
8081
RNSignerClientParamsSchema.parse(params);
8182

8283
super({
83-
stamper: NativeTEKStamper,
84+
stamper: SESSION_STAMPER,
8485
rootOrgId: rootOrgId ?? "24c1acf5-810f-41e0-a503-d5d13fa8e830",
8586
connection,
8687
});
@@ -93,7 +94,7 @@ export class RNSignerClient extends BaseSignerClient<
9394
args: Omit<OtpParams, "targetPublicKey">,
9495
): Promise<SubmitOtpCodeResponse> {
9596
this.eventEmitter.emit("authenticating", { type: "otpVerify" });
96-
const publicKey = await this.stamper.init();
97+
const publicKey = await this.initSessionStamper();
9798

9899
const response = await this.request("/v1/otp", {
99100
...args,
@@ -130,7 +131,7 @@ export class RNSignerClient extends BaseSignerClient<
130131
params: Omit<EmailAuthParams, "targetPublicKey">,
131132
): Promise<{ orgId: string; otpId?: string; multiFactors?: MfaFactor[] }> {
132133
this.eventEmitter.emit("authenticating", { type: "email" });
133-
const targetPublicKey = await this.stamper.init();
134+
const targetPublicKey = await this.initSessionStamper();
134135

135136
try {
136137
return await this.request("/v1/auth", {
@@ -156,7 +157,7 @@ export class RNSignerClient extends BaseSignerClient<
156157
): Promise<{ orgId: string; otpId?: string }> {
157158
this.eventEmitter.emit("authenticating", { type: "sms" });
158159
const { phone } = params;
159-
const targetPublicKey = await this.stamper.init();
160+
const targetPublicKey = await this.initSessionStamper();
160161

161162
return this.request("/v1/auth", {
162163
phone,
@@ -169,7 +170,7 @@ export class RNSignerClient extends BaseSignerClient<
169170
): Promise<JwtResponse> {
170171
this.eventEmitter.emit("authenticating", { type: "custom-jwt" });
171172

172-
const publicKey = await this.stamper.init();
173+
const publicKey = await this.initSessionStamper();
173174
return this.request("/v1/auth-jwt", {
174175
jwt: args.jwt,
175176
targetPublicKey: publicKey,
@@ -194,9 +195,9 @@ export class RNSignerClient extends BaseSignerClient<
194195
type: params.authenticatingType,
195196
});
196197

197-
await this.stamper.init();
198+
await this.initSessionStamper();
198199

199-
const result = await this.stamper.injectCredentialBundle(params.bundle);
200+
const result = await SESSION_STAMPER.injectCredentialBundle(params.bundle);
200201

201202
if (!result) {
202203
throw new Error("Failed to inject credential bundle");
@@ -223,7 +224,7 @@ export class RNSignerClient extends BaseSignerClient<
223224
this.eventEmitter.emit("authenticating", { type: "oauth" });
224225

225226
const oauthParams = args;
226-
const turnkeyPublicKey = await this.stamper.init();
227+
const turnkeyPublicKey = await this.initSessionStamper();
227228
const oauthCallbackUrl = this.oauthCallbackUrl;
228229
const oauthConfig = await this.getOauthConfig();
229230
const providerUrl = await this.getOauthProviderUrl({
@@ -294,8 +295,8 @@ export class RNSignerClient extends BaseSignerClient<
294295

295296
override async disconnect(): Promise<void> {
296297
this.user = undefined;
297-
this.stamper.clear();
298-
await this.stamper.init();
298+
SESSION_STAMPER.clear();
299+
await this.initSessionStamper();
299300
}
300301

301302
/**
@@ -426,7 +427,7 @@ export class RNSignerClient extends BaseSignerClient<
426427
}
427428

428429
override targetPublicKey(): Promise<string> {
429-
return this.stamper.init();
430+
return this.initSessionStamper();
430431
}
431432

432433
protected override getWebAuthnAttestation = async (
@@ -461,14 +462,34 @@ export class RNSignerClient extends BaseSignerClient<
461462
};
462463

463464
protected override getOauthConfig = async (): Promise<OauthConfig> => {
464-
const publicKey = await this.stamper.init();
465+
const currentStamper = this.turnkeyClient.stamper;
466+
const publicKey = await this.initSessionStamper();
465467

468+
// swap the stamper back in case the user logged in with a different stamper (passkeys)
469+
this.setStamper(currentStamper);
466470
const nonce = this.getOauthNonce(publicKey);
467471
return this.request("/v1/prepare-oauth", { nonce });
468472
};
469473

474+
private initSessionStamperPromise: Promise<string> | null = null;
475+
470476
protected override async initSessionStamper(): Promise<string> {
471-
return this.stamper.init();
477+
if (this.initSessionStamperPromise) {
478+
return this.initSessionStamperPromise;
479+
}
480+
481+
this.initSessionStamperPromise = (async () => {
482+
await SESSION_STAMPER.init();
483+
this.setStamper(SESSION_STAMPER);
484+
return SESSION_STAMPER.publicKey()!;
485+
})();
486+
487+
try {
488+
const result = await this.initSessionStamperPromise;
489+
return result;
490+
} finally {
491+
this.initSessionStamperPromise = null;
492+
}
472493
}
473494

474495
protected override async initWebauthnStamper(

0 commit comments

Comments
 (0)