Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions examples/react/src/firebase/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@
import { initializeApp, getApps } from "firebase/app";
import { firebaseConfig } from "./config";
import { connectAuthEmulator, getAuth } from "firebase/auth";
import { autoAnonymousLogin, initializeUI } from "@firebase-ui/core";
import { autoAnonymousLogin, initializeUI, oneTapSignIn } from "@firebase-ui/core";

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

export const auth = getAuth(firebaseApp);

export const ui = initializeUI({
app: firebaseApp,
behaviors: [autoAnonymousLogin()],
behaviors: [autoAnonymousLogin(), oneTapSignIn({
clientId: '200312857118-lscdui98fkaq7ffr81446blafjn5o6r0.apps.googleusercontent.com',
})],
});

if (import.meta.env.MODE === "development") {
Expand Down
5 changes: 3 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"zod": "catalog:"
},
"devDependencies": {
"@types/google-one-tap": "^1.2.6",
"@types/jsdom": "catalog:",
"firebase": "catalog:",
"jsdom": "catalog:",
Expand All @@ -60,7 +61,7 @@
"tsup": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vitest-tsconfig-paths": "catalog:",
"vitest": "catalog:"
"vitest": "catalog:",
"vitest-tsconfig-paths": "catalog:"
}
}
190 changes: 152 additions & 38 deletions packages/core/src/auth.test.ts

Large diffs are not rendered by default.

28 changes: 19 additions & 9 deletions packages/core/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ import {
sendSignInLinkToEmail as _sendSignInLinkToEmail,
signInAnonymously as _signInAnonymously,
signInWithPhoneNumber as _signInWithPhoneNumber,
signInWithCredential as _signInWithCredential,
ActionCodeSettings,
ApplicationVerifier,
AuthProvider,
ConfirmationResult,
EmailAuthProvider,
linkWithCredential,
PhoneAuthProvider,
signInWithCredential,
signInWithRedirect,
UserCredential,
AuthCredential,
} from "firebase/auth";
import { FirebaseUIConfiguration } from "./config";
import { handleFirebaseError } from "./errors";
Expand Down Expand Up @@ -70,7 +71,7 @@ export async function signInWithEmailAndPassword(
}

ui.setState("pending");
const result = await signInWithCredential(ui.auth, credential);
const result = await _signInWithCredential(ui.auth, credential);
return handlePendingCredential(ui, result);
} catch (error) {
handleFirebaseError(ui, error);
Expand Down Expand Up @@ -138,7 +139,7 @@ export async function confirmPhoneNumber(
}

ui.setState("pending");
const result = await signInWithCredential(ui.auth, credential);
const result = await _signInWithCredential(ui.auth, credential);
return handlePendingCredential(ui, result);
} catch (error) {
handleFirebaseError(ui, error);
Expand Down Expand Up @@ -182,18 +183,27 @@ export async function signInWithEmailLink(
email: string,
link: string
): Promise<UserCredential> {
try {
const credential = EmailAuthProvider.credentialWithLink(email, link);
const credential = EmailAuthProvider.credentialWithLink(email, link);
return signInWithCredential(ui, credential);
}

export async function signInWithCredential(
ui: FirebaseUIConfiguration,
credential: AuthCredential
): Promise<UserCredential> {
try {
if (hasBehavior(ui, "autoUpgradeAnonymousCredential")) {
const result = await getBehavior(ui, "autoUpgradeAnonymousCredential")(ui, credential);
if (result) {
return handlePendingCredential(ui, result);
const userCredential = await getBehavior(ui, "autoUpgradeAnonymousCredential")(ui, credential);

// If they got here, they're either not anonymous or they've been linked.
// If the credential has been linked, we don't need to sign them in, so return early.
if (userCredential) {
return handlePendingCredential(ui, userCredential);
}
}

ui.setState("pending");
const result = await signInWithCredential(ui.auth, credential);
const result = await _signInWithCredential(ui.auth, credential);
return handlePendingCredential(ui, result);
} catch (error) {
handleFirebaseError(ui, error);
Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/behaviors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { RecaptchaVerifier } from "firebase/auth";
import * as anonymousUpgradeHandlers from "./anonymous-upgrade";
import * as autoAnonymousLoginHandlers from "./auto-anonymous-login";
import * as recaptchaHandlers from "./recaptcha";
import * as oneTapSignInHandlers from "./one-tap";
import {
callableBehavior,
initBehavior,
Expand All @@ -22,6 +23,7 @@ type Registry = {
typeof anonymousUpgradeHandlers.autoUpgradeAnonymousUserRedirectHandler
>;
recaptchaVerification: CallableBehavior<(ui: FirebaseUIConfiguration, element: HTMLElement) => RecaptchaVerifier>;
oneTapSignIn: InitBehavior<(ui: FirebaseUIConfiguration) => ReturnType<typeof oneTapSignInHandlers.oneTapSignInHandler>>;
};

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

export type OneTapSignInOptions = oneTapSignInHandlers.OneTapSignInOptions;

export function oneTapSignIn(options: OneTapSignInOptions): Behavior<"oneTapSignIn"> {
return {
oneTapSignIn: initBehavior((ui) => oneTapSignInHandlers.oneTapSignInHandler(ui, options)),
};
}

export function hasBehavior<T extends keyof Registry>(ui: FirebaseUIConfiguration, key: T): boolean {
return !!ui.behaviors[key];
}
Expand Down
Loading
Loading