Skip to content

Commit 67e15da

Browse files
committed
feat(core): Add provider strategy
1 parent e3ec627 commit 67e15da

File tree

4 files changed

+62
-16
lines changed

4 files changed

+62
-16
lines changed

packages/core/src/auth.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import {
2929
linkWithCredential,
3030
PhoneAuthProvider,
3131
signInWithCredential,
32-
signInWithRedirect,
3332
UserCredential,
3433
} from "firebase/auth";
3534
import { FirebaseUIConfiguration } from "./config";
@@ -214,20 +213,24 @@ export async function signInAnonymously(ui: FirebaseUIConfiguration): Promise<Us
214213
}
215214
}
216215

217-
export async function signInWithProvider(ui: FirebaseUIConfiguration, provider: AuthProvider): Promise<void> {
216+
export async function signInWithProvider(ui: FirebaseUIConfiguration, provider: AuthProvider): Promise<UserCredential | never> {
218217
try {
219218
if (hasBehavior(ui, "autoUpgradeAnonymousProvider")) {
220-
await getBehavior(ui, "autoUpgradeAnonymousProvider")(ui, provider);
221-
// If we get to here, the user is not anonymous, otherwise they
222-
// have been redirected to the provider's sign in page.
219+
const credential = await getBehavior(ui, "autoUpgradeAnonymousProvider")(ui, provider);
220+
221+
// If we got here, the user is either not anonymous, or they have been linked
222+
// via a popup, and the credential has been created.
223+
if (credential) {
224+
return handlePendingCredential(ui, credential);
225+
}
223226
}
224227

225-
ui.setState("pending");
228+
const strategy = getBehavior(ui, "providerSignInStrategy");
229+
const result = await strategy(ui, provider);
226230

227-
// TODO(ehesp): Handle popup or redirect based on behavior
228-
await signInWithRedirect(ui.auth, provider);
229-
// We don't modify state here since the user is redirected.
230-
// If we support popups, we'd need to modify state here.
231+
// If we got here, the user has been signed in via a popup.
232+
// Otherwise, they will have been redirected.
233+
return handlePendingCredential(ui, result);
231234
} catch (error) {
232235
handleFirebaseError(ui, error);
233236
} finally {

packages/core/src/behaviors/anonymous-upgrade.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { AuthCredential, AuthProvider, linkWithCredential, linkWithRedirect } from "firebase/auth";
22
import { FirebaseUIConfiguration } from "~/config";
33
import { RedirectHandler } from "./utils";
4+
import { getBehavior } from "~/behaviors";
45

56
export const autoUpgradeAnonymousCredentialHandler = async (ui: FirebaseUIConfiguration, credential: AuthCredential) => {
67
const currentUser = ui.auth.currentUser;
78

8-
// Check if the user is anonymous. If not, we can't upgrade them.
99
if (!currentUser?.isAnonymous) {
1010
return;
1111
}
@@ -24,11 +24,7 @@ export const autoUpgradeAnonymousProviderHandler = async (ui: FirebaseUIConfigur
2424
return;
2525
}
2626

27-
ui.setState("pending");
28-
// TODO... this should use redirect OR popup
29-
await linkWithRedirect(currentUser, provider);
30-
// We don't modify state here since the user is redirected.
31-
// If we support popups, we'd need to modify state here.
27+
return getBehavior(ui, "providerLinkStrategy")(ui, currentUser, provider);
3228
};
3329

3430
export const autoUpgradeAnonymousUserRedirectHandler: RedirectHandler = async () => {

packages/core/src/behaviors/index.ts

Lines changed: 18 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 providerStrategyHandlers from "./provider-strategy";
67
import {
78
callableBehavior,
89
initBehavior,
@@ -22,6 +23,8 @@ type Registry = {
2223
typeof anonymousUpgradeHandlers.autoUpgradeAnonymousUserRedirectHandler
2324
>;
2425
recaptchaVerification: CallableBehavior<(ui: FirebaseUIConfiguration, element: HTMLElement) => RecaptchaVerifier>;
26+
providerSignInStrategy: CallableBehavior<providerStrategyHandlers.ProviderSignInStrategyHandler>;
27+
providerLinkStrategy: CallableBehavior<providerStrategyHandlers.ProviderLinkStrategyHandler>;
2528
};
2629

2730
export type Behavior<T extends keyof Registry = keyof Registry> = Pick<Registry, T>;
@@ -55,6 +58,20 @@ export function recaptchaVerification(options?: RecaptchaVerificationOptions): B
5558
};
5659
}
5760

61+
export function providerRedirectStrategy(): Behavior<"providerSignInStrategy" | "providerLinkStrategy"> {
62+
return {
63+
providerSignInStrategy: callableBehavior(providerStrategyHandlers.signInWithRediectHandler),
64+
providerLinkStrategy: callableBehavior(providerStrategyHandlers.linkWithRedirectHandler),
65+
};
66+
}
67+
68+
export function providerPopupStrategy(): Behavior<"providerSignInStrategy" | "providerLinkStrategy"> {
69+
return {
70+
providerSignInStrategy: callableBehavior(providerStrategyHandlers.signInWithPopupHandler),
71+
providerLinkStrategy: callableBehavior(providerStrategyHandlers.linkWithPopupHandler),
72+
};
73+
}
74+
5875
export function hasBehavior<T extends keyof Registry>(ui: FirebaseUIConfiguration, key: T): boolean {
5976
return !!ui.behaviors[key];
6077
}
@@ -69,4 +86,5 @@ export function getBehavior<T extends keyof Registry>(ui: FirebaseUIConfiguratio
6986

7087
export const defaultBehaviors: Behavior<"recaptchaVerification"> = {
7188
...recaptchaVerification(),
89+
...providerRedirectStrategy(),
7290
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { AuthProvider, linkWithPopup, linkWithRedirect, signInWithPopup, signInWithRedirect, User, UserCredential } from "firebase/auth";
2+
import { FirebaseUIConfiguration } from "~/config";
3+
4+
export type ProviderSignInStrategyHandler = (ui: FirebaseUIConfiguration, provider: AuthProvider) => Promise<never | UserCredential>
5+
export type ProviderLinkStrategyHandler = (ui: FirebaseUIConfiguration, user: User, provider: AuthProvider) => Promise<never | UserCredential>;
6+
7+
export const signInWithRediectHandler: ProviderSignInStrategyHandler = async (ui, provider) => {
8+
ui.setState("pending");
9+
return signInWithRedirect(ui.auth, provider);
10+
};
11+
12+
export const signInWithPopupHandler: ProviderSignInStrategyHandler = async (ui, provider) => {
13+
ui.setState("pending");
14+
const result = await signInWithPopup(ui.auth, provider);
15+
ui.setState("idle");
16+
return result;
17+
};
18+
19+
export const linkWithRedirectHandler: ProviderLinkStrategyHandler = async (ui, user, provider) => {
20+
ui.setState("pending");
21+
return linkWithRedirect(user, provider);
22+
};
23+
24+
export const linkWithPopupHandler: ProviderLinkStrategyHandler = async (ui, user, provider) => {
25+
ui.setState("pending");
26+
const result = await linkWithPopup(user, provider);
27+
ui.setState("idle");
28+
return result;
29+
};

0 commit comments

Comments
 (0)