Skip to content

Commit ee57c38

Browse files
committed
feat(core): Add oneTapSignIn behavior
1 parent f0f9414 commit ee57c38

File tree

9 files changed

+640
-153
lines changed

9 files changed

+640
-153
lines changed

examples/react/src/firebase/firebase.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@
1919
import { initializeApp, getApps } from "firebase/app";
2020
import { firebaseConfig } from "./config";
2121
import { connectAuthEmulator, getAuth } from "firebase/auth";
22-
import { autoAnonymousLogin, initializeUI } from "@firebase-ui/core";
22+
import { autoAnonymousLogin, initializeUI, oneTapSignIn } from "@firebase-ui/core";
2323

2424
export const firebaseApp = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
2525

2626
export const auth = getAuth(firebaseApp);
2727

2828
export const ui = initializeUI({
2929
app: firebaseApp,
30-
behaviors: [autoAnonymousLogin()],
30+
behaviors: [autoAnonymousLogin(), oneTapSignIn({
31+
clientId: '200312857118-lscdui98fkaq7ffr81446blafjn5o6r0.apps.googleusercontent.com',
32+
})],
3133
});
3234

3335
if (import.meta.env.MODE === "development") {

packages/core/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"zod": "catalog:"
5353
},
5454
"devDependencies": {
55+
"@types/google-one-tap": "^1.2.6",
5556
"@types/jsdom": "catalog:",
5657
"firebase": "catalog:",
5758
"jsdom": "catalog:",
@@ -60,7 +61,7 @@
6061
"tsup": "catalog:",
6162
"typescript": "catalog:",
6263
"vite": "catalog:",
63-
"vitest-tsconfig-paths": "catalog:",
64-
"vitest": "catalog:"
64+
"vitest": "catalog:",
65+
"vitest-tsconfig-paths": "catalog:"
6566
}
6667
}

packages/core/src/auth.test.ts

Lines changed: 152 additions & 38 deletions
Large diffs are not rendered by default.

packages/core/src/auth.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,17 @@ import {
2121
sendSignInLinkToEmail as _sendSignInLinkToEmail,
2222
signInAnonymously as _signInAnonymously,
2323
signInWithPhoneNumber as _signInWithPhoneNumber,
24+
signInWithCredential as _signInWithCredential,
2425
ActionCodeSettings,
2526
ApplicationVerifier,
2627
AuthProvider,
2728
ConfirmationResult,
2829
EmailAuthProvider,
2930
linkWithCredential,
3031
PhoneAuthProvider,
31-
signInWithCredential,
3232
signInWithRedirect,
3333
UserCredential,
34+
AuthCredential,
3435
} from "firebase/auth";
3536
import { FirebaseUIConfiguration } from "./config";
3637
import { handleFirebaseError } from "./errors";
@@ -70,7 +71,7 @@ export async function signInWithEmailAndPassword(
7071
}
7172

7273
ui.setState("pending");
73-
const result = await signInWithCredential(ui.auth, credential);
74+
const result = await _signInWithCredential(ui.auth, credential);
7475
return handlePendingCredential(ui, result);
7576
} catch (error) {
7677
handleFirebaseError(ui, error);
@@ -138,7 +139,7 @@ export async function confirmPhoneNumber(
138139
}
139140

140141
ui.setState("pending");
141-
const result = await signInWithCredential(ui.auth, credential);
142+
const result = await _signInWithCredential(ui.auth, credential);
142143
return handlePendingCredential(ui, result);
143144
} catch (error) {
144145
handleFirebaseError(ui, error);
@@ -182,18 +183,27 @@ export async function signInWithEmailLink(
182183
email: string,
183184
link: string
184185
): Promise<UserCredential> {
185-
try {
186-
const credential = EmailAuthProvider.credentialWithLink(email, link);
186+
const credential = EmailAuthProvider.credentialWithLink(email, link);
187+
return signInWithCredential(ui, credential);
188+
}
187189

190+
export async function signInWithCredential(
191+
ui: FirebaseUIConfiguration,
192+
credential: AuthCredential
193+
): Promise<UserCredential> {
194+
try {
188195
if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) {
189-
const result = await getBehavior(ui, "autoUpgradeAnonymousCredential")(ui, credential);
190-
if (result) {
191-
return handlePendingCredential(ui, result);
196+
const userCredential = await getBehavior(ui, "autoUpgradeAnonymousCredential")(ui, credential);
197+
198+
// If they got here, they're either not anonymous or they've been linked.
199+
// If the credential has been linked, we don't need to sign them in, so return early.
200+
if (userCredential) {
201+
return handlePendingCredential(ui, userCredential);
192202
}
193203
}
194204

195205
ui.setState("pending");
196-
const result = await signInWithCredential(ui.auth, credential);
206+
const result = await _signInWithCredential(ui.auth, credential);
197207
return handlePendingCredential(ui, result);
198208
} catch (error) {
199209
handleFirebaseError(ui, error);

packages/core/src/behaviors/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { RecaptchaVerifier } from "firebase/auth";
33
import * as anonymousUpgradeHandlers from "./anonymous-upgrade";
44
import * as autoAnonymousLoginHandlers from "./auto-anonymous-login";
55
import * as recaptchaHandlers from "./recaptcha";
6+
import * as oneTapSignInHandlers from "./one-tap";
67
import {
78
callableBehavior,
89
initBehavior,
@@ -22,6 +23,7 @@ type Registry = {
2223
typeof anonymousUpgradeHandlers.autoUpgradeAnonymousUserRedirectHandler
2324
>;
2425
recaptchaVerification: CallableBehavior<(ui: FirebaseUIConfiguration, element: HTMLElement) => RecaptchaVerifier>;
26+
oneTapSignIn: InitBehavior<(ui: FirebaseUIConfiguration) => ReturnType<typeof oneTapSignInHandlers.oneTapSignInHandler>>;
2527
};
2628

2729
export type Behavior<T extends keyof Registry = keyof Registry> = Pick<Registry, T>;
@@ -55,6 +57,14 @@ export function recaptchaVerification(options?: RecaptchaVerificationOptions): B
5557
};
5658
}
5759

60+
export type OneTapSignInOptions = oneTapSignInHandlers.OneTapSignInOptions;
61+
62+
export function oneTapSignIn(options: OneTapSignInOptions): Behavior<"oneTapSignIn"> {
63+
return {
64+
oneTapSignIn: initBehavior((ui) => oneTapSignInHandlers.oneTapSignInHandler(ui, options)),
65+
};
66+
}
67+
5868
export function hasBehavior<T extends keyof Registry>(ui: FirebaseUIConfiguration, key: T): boolean {
5969
return !!ui.behaviors[key];
6070
}

0 commit comments

Comments
 (0)