Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
FirebaseUI Web
https://github.com/firebase/firebaseui-web
Admin
FirebaseUI is an open-source JavaScript library for Web that provides simple, customizable UI
...
Tokens:
45,505
Snippets:
548
Trust Score:
8.2
Update:
4 days ago
Context
Skills
Chat
Benchmark
82.4
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# FirebaseUI for Web (v7) FirebaseUI for Web is a complete, framework-native authentication UI library built on top of the Firebase JS SDK. It provides composable, ready-to-use authentication components for React, Angular, and Shadcn, covering email/password, email link, phone (SMS), OAuth providers (Google, Apple, GitHub, Facebook, Microsoft, Twitter, Yahoo), and full multi-factor authentication (MFA) flows via SMS and TOTP. The library is structured as a monorepo with a framework-agnostic core package (`@firebase-oss/ui-core`) that manages a reactive `FirebaseUIStore` using nanostores, plus framework-specific packages (`@firebase-oss/ui-react` and `@firebase-oss/ui-angular`) that consume it. A separate `@firebase-oss/ui-styles` package provides default CSS styling with full theming support via CSS variables. The architecture separates UI into **Screens** (opinionated, card-wrapped full views) and **Forms** (unstyled logic-only components), enabling drop-in integration or bespoke UI construction. Behavior is customizable through a composable plugin system called **Behaviors**, which control automatic anonymous login, anonymous user upgrade, reCAPTCHA strategy, provider popup/redirect mode, Google One Tap, display name requirements, and country code filtering. All user-facing strings are fully localizable via the `@firebase-oss/ui-translations` package, with English (`enUs`) provided out of the box. The library handles complex flows automatically including account-exists-with-different-credential linking, MFA challenge capture, redirect result processing, and pending credential persistence across page navigations. --- ## `@firebase-oss/ui-core` ### `initializeUI` — Initialize the FirebaseUI reactive store Creates and returns a `FirebaseUIStore` (a nanostores `DeepMapStore`) that drives all UI state, locale, and behavior. Must be called once at application startup and passed to the framework provider. ```typescript import { initializeApp } from 'firebase/app'; import { initializeUI, requireDisplayName, autoUpgradeAnonymousUsers, oneTapSignIn, providerRedirectStrategy, countryCodes, } from '@firebase-oss/ui-core'; import { registerLocale } from '@firebase-oss/ui-translations'; const app = initializeApp({ apiKey: 'AIza...', authDomain: 'my-project.firebaseapp.com', projectId: 'my-project', }); const frFr = registerLocale('fr-FR', { labels: { signIn: 'Se connecter' }, }); const ui = initializeUI( { app, locale: frFr, // optional; defaults to enUs behaviors: [ requireDisplayName(), autoUpgradeAnonymousUsers({ async onUpgrade(ui, oldUserId, credential) { // merge anonymous user data into the new account await mergeUserData(oldUserId, credential.user.uid); }, }), oneTapSignIn({ clientId: 'GOOGLE_CLIENT_ID', autoSelect: false }), providerRedirectStrategy(), // use redirect instead of popup for OAuth countryCodes({ allowedCountries: ['US', 'GB'], defaultCountry: 'US' }), ], }, '[DEFAULT]' // optional instance name ); // Subscribe to store changes in plain JS ui.listen((state) => { console.log('UI state:', state.state); // 'idle' | 'pending' | 'loading' console.log('Locale:', state.locale); if (state.multiFactorResolver) { console.log('MFA required!'); } if (state.redirectError) { console.error('Redirect error:', state.redirectError.message); } }); // Dynamically change locale ui.get().setLocale(frFr); ``` --- ### `signInWithEmailAndPassword` — Sign in with email and password Signs in a user using an `EmailAuthProvider` credential. Automatically manages `pending` UI state, handles the `autoUpgradeAnonymousCredential` behavior, links any pending credentials stored in `sessionStorage`, and throws a localized `FirebaseUIError` on failure. ```typescript import { signInWithEmailAndPassword, FirebaseUIError } from '@firebase-oss/ui-core'; async function handleSignIn(ui, email: string, password: string) { try { const credential = await signInWithEmailAndPassword(ui, email, password); console.log('Signed in as:', credential.user.uid); // Expected: credential.user is the Firebase User object } catch (error) { if (error instanceof FirebaseUIError) { // Localized message, e.g. "No user found with this email." console.error(error.message); } } } ``` --- ### `createUserWithEmailAndPassword` — Create a new user account Registers a new user with email and password. Enforces the `requireDisplayName` behavior if enabled, and upgrades anonymous users if `autoUpgradeAnonymousCredential` is configured. ```typescript import { createUserWithEmailAndPassword, FirebaseUIError } from '@firebase-oss/ui-core'; async function handleSignUp(ui, email: string, password: string, displayName: string) { try { const credential = await createUserWithEmailAndPassword(ui, email, password, displayName); console.log('New user UID:', credential.user.uid); console.log('Display name set:', credential.user.displayName); } catch (error) { if (error instanceof FirebaseUIError) { // e.g. "Password should be at least 6 characters." or "Display name is required." console.error(error.message); } } } ``` --- ### `signInWithProvider` — Sign in with an OAuth provider Signs in using any Firebase `AuthProvider` (Google, Apple, GitHub, etc.) using the configured strategy (popup by default, redirect if `providerRedirectStrategy()` is used). Handles anonymous user upgrade and pending credential linking automatically. ```typescript import { signInWithProvider } from '@firebase-oss/ui-core'; import { GoogleAuthProvider, GithubAuthProvider, OAuthProvider } from 'firebase/auth'; // Google sign-in (popup by default) const googleCredential = await signInWithProvider(ui, new GoogleAuthProvider()); // GitHub sign-in const githubCredential = await signInWithProvider(ui, new GithubAuthProvider()); // Custom OIDC/SAML provider const oidcProvider = new OAuthProvider('oidc.my-provider'); const oidcCredential = await signInWithProvider(ui, oidcProvider); // If redirect strategy: function navigates away, returns never. // If popup strategy: resolves with UserCredential. ``` --- ### `sendSignInLinkToEmail` / `completeEmailLinkSignIn` — Email link (passwordless) sign-in Sends a sign-in link to the user's email and stores the address in `localStorage`. After the user clicks the link, call `completeEmailLinkSignIn` on the landing page to finish the flow. ```typescript import { sendSignInLinkToEmail, completeEmailLinkSignIn } from '@firebase-oss/ui-core'; // Step 1: Send the link (on your sign-in page) await sendSignInLinkToEmail(ui, 'user@example.com'); // Email stored in localStorage['emailForSignIn'] // actionCodeSettings.url is automatically set to window.location.href // Step 2: Complete sign-in (on the landing page — same or different page) const credential = await completeEmailLinkSignIn(ui, window.location.href); if (credential) { console.log('Signed in via email link:', credential.user.email); } else { // URL was not a valid email sign-in link, or no stored email found console.log('Not a sign-in link or email missing from localStorage'); } ``` --- ### `verifyPhoneNumber` / `confirmPhoneNumber` — Phone (SMS) authentication Two-step SMS authentication. First verify the phone number to receive a `verificationId`, then confirm with the 6-digit SMS code. ```typescript import { verifyPhoneNumber, confirmPhoneNumber } from '@firebase-oss/ui-core'; import { RecaptchaVerifier } from 'firebase/auth'; // Step 1: Verify phone number (triggers SMS) const recaptchaContainer = document.getElementById('recaptcha-container')!; const appVerifier = new RecaptchaVerifier(ui.auth, recaptchaContainer, { size: 'invisible' }); const verificationId = await verifyPhoneNumber(ui, '+14155552671', appVerifier); // Step 2: Confirm with the SMS code const credential = await confirmPhoneNumber(ui, verificationId, '123456'); console.log('Phone auth UID:', credential.user.uid); // MFA enrollment flow (pass mfaUser): const mfaUser = multiFactor(ui.auth.currentUser!); const enrollVerificationId = await verifyPhoneNumber(ui, '+14155552671', appVerifier, mfaUser); // MFA assertion flow (pass mfaHint): const mfaHint = ui.multiFactorResolver!.hints[0]; const assertVerificationId = await verifyPhoneNumber(ui, '', appVerifier, undefined, mfaHint); ``` --- ### `sendPasswordResetEmail` — Send password reset email ```typescript import { sendPasswordResetEmail, FirebaseUIError } from '@firebase-oss/ui-core'; try { await sendPasswordResetEmail(ui, 'user@example.com'); console.log('Password reset email sent successfully.'); } catch (error) { if (error instanceof FirebaseUIError) { console.error(error.message); // e.g. "No user found with this email." } } ``` --- ### `signInWithCustomToken` — Sign in with a custom token ```typescript import { signInWithCustomToken } from '@firebase-oss/ui-core'; // Token obtained from your custom auth server const token = await fetchCustomToken('/api/auth/token'); const credential = await signInWithCustomToken(ui, token); console.log('Signed in with custom token, UID:', credential.user.uid); ``` --- ### `signInAnonymously` — Anonymous sign-in ```typescript import { signInAnonymously } from '@firebase-oss/ui-core'; const credential = await signInAnonymously(ui); console.log('Anonymous UID:', credential.user.uid); console.log('Is anonymous:', credential.user.isAnonymous); // true ``` --- ### `signInWithMultiFactorAssertion` / `enrollWithMultiFactorAssertion` — MFA resolution and enrollment Resolve a pending MFA challenge or enroll a new MFA method for the current user. ```typescript import { signInWithMultiFactorAssertion, enrollWithMultiFactorAssertion, generateTotpSecret, generateTotpQrCode, } from '@firebase-oss/ui-core'; import { PhoneMultiFactorGenerator, TotpMultiFactorGenerator } from 'firebase/auth'; // Resolve an SMS MFA challenge (ui.multiFactorResolver is set automatically on error) const smsAssertion = PhoneMultiFactorGenerator.assertion( PhoneAuthProvider.credential(verificationId, '654321') ); const credential = await signInWithMultiFactorAssertion(ui, smsAssertion); // Enroll TOTP MFA for the current user const secret = await generateTotpSecret(ui); const qrDataUrl = generateTotpQrCode(ui, secret, 'user@example.com', 'MyApp'); // Render qrDataUrl in an <img> for the user to scan with their authenticator app const totpCode = '123456'; // entered by user from their authenticator app const totpAssertion = TotpMultiFactorGenerator.assertionForEnrollment(secret, totpCode); await enrollWithMultiFactorAssertion(ui, totpAssertion, 'My Authenticator'); ``` --- ### `signInWithCredential` — Sign in with an `AuthCredential` ```typescript import { signInWithCredential } from '@firebase-oss/ui-core'; import { GoogleAuthProvider } from 'firebase/auth'; const idToken = 'google-id-token-from-native-sdk'; const credential = GoogleAuthProvider.credential(idToken); const result = await signInWithCredential(ui, credential); console.log('UID:', result.user.uid); ``` --- ### Behaviors — Composable plugins for authentication flow customization Behaviors are passed to `initializeUI` to extend the default authentication logic. ```typescript import { initializeUI, autoAnonymousLogin, autoUpgradeAnonymousUsers, requireDisplayName, recaptchaVerification, providerPopupStrategy, providerRedirectStrategy, oneTapSignIn, countryCodes, hasBehavior, getBehavior, } from '@firebase-oss/ui-core'; const ui = initializeUI({ app, behaviors: [ // Automatically sign users in anonymously on init autoAnonymousLogin(), // Upgrade anonymous user when they sign in with a real credential autoUpgradeAnonymousUsers({ async onUpgrade(ui, oldUserId, credential) { await mergeUserData(oldUserId, credential.user.uid); }, }), // Require display name during sign-up requireDisplayName(), // Google One Tap oneTapSignIn({ clientId: 'GOOGLE_CLIENT_ID', autoSelect: true }), // Custom reCAPTCHA config recaptchaVerification({ size: 'normal', theme: 'dark' }), // Use redirect for OAuth (default is popup) providerRedirectStrategy(), // Phone country code filtering countryCodes({ allowedCountries: ['US', 'CA', 'GB'], defaultCountry: 'US' }), ], }); // Check if a behavior is active if (hasBehavior(ui.get(), 'requireDisplayName')) { console.log('Display name is required on sign-up.'); } // Call a behavior's handler directly const recaptchaVerifier = getBehavior(ui.get(), 'recaptchaVerification')( ui.get(), document.getElementById('recaptcha-container')! ); ``` --- ### `getTranslation` — Get a localized string ```typescript import { getTranslation } from '@firebase-oss/ui-core'; const signInLabel = getTranslation(ui.get(), 'labels', 'signIn'); // → "Sign in" const errorMsg = getTranslation(ui.get(), 'errors', 'userNotFound'); // → "No user found with this email." const promptMsg = getTranslation(ui.get(), 'prompts', 'signInToAccount'); // → "Sign in to your account." ``` --- ### `FirebaseUIError` / `handleFirebaseError` — Localized error handling `FirebaseUIError` extends `FirebaseError` and provides a locale-aware message. `handleFirebaseError` is called internally by all auth functions, but can be used in custom flows. ```typescript import { handleFirebaseError, FirebaseUIError } from '@firebase-oss/ui-core'; import { signInWithEmailAndPassword as firebaseSignIn } from 'firebase/auth'; // Wrap a raw Firebase call in FirebaseUI error handling async function customSignIn(ui, email: string, password: string) { try { return await firebaseSignIn(ui.auth, email, password); } catch (error) { handleFirebaseError(ui, error); // ^ throws FirebaseUIError with translated message // Also: sets ui.multiFactorResolver for auth/multi-factor-auth-required // Also: saves pending credential for auth/account-exists-with-different-credential } } try { await customSignIn(ui, 'user@example.com', 'wrongpassword'); } catch (error) { if (error instanceof FirebaseUIError) { console.error(error.message); // Translated: "Incorrect password. Please try again." console.error(error.code); // Original Firebase code: "auth/wrong-password" } } ``` --- ### Zod form schemas — Validation schemas for auth forms ```typescript import { createSignInAuthFormSchema, createSignUpAuthFormSchema, createForgotPasswordAuthFormSchema, createEmailLinkAuthFormSchema, createPhoneAuthNumberFormSchema, createPhoneAuthVerifyFormSchema, createMultiFactorPhoneAuthNumberFormSchema, createMultiFactorTotpAuthVerifyFormSchema, } from '@firebase-oss/ui-core'; const ui = initializeUI({ app, behaviors: [requireDisplayName()] }); const instance = ui.get(); const signInSchema = createSignInAuthFormSchema(instance); // { email: z.string().email(...), password: z.string().min(6, ...) } const signUpSchema = createSignUpAuthFormSchema(instance); // { email, password, displayName: z.string().min(1, ...) } ← required because requireDisplayName is active const phoneSchema = createPhoneAuthNumberFormSchema(instance); // { phoneNumber: z.string().min(1).max(10) } const totpVerifySchema = createMultiFactorTotpAuthVerifyFormSchema(instance); // { verificationCode: z.string().refine(val => val.length === 6) } // Use with any form library: const result = signInSchema.safeParse({ email: 'bad-email', password: '123' }); console.log(result.success); // false console.log(result.error?.errors); // [{ message: 'Invalid email address' }, { message: 'Password should be at least 6 characters.' }] ``` --- ### `countryData` / `formatPhoneNumber` — Country and phone number utilities ```typescript import { countryData, formatPhoneNumber } from '@firebase-oss/ui-core'; // Find a country const us = countryData.find(c => c.code === 'US'); console.log(us); // { name: 'United States', dialCode: '+1', code: 'US', emoji: '🇺🇸' } // Format a phone number into E164 format for Firebase const formatted = formatPhoneNumber('4155552671', us!); console.log(formatted); // '+14155552671' ``` --- ## `@firebase-oss/ui-react` ### `FirebaseUIProvider` — React context provider Wraps the application and provides the `FirebaseUI` reactive state to all child components via React context. ```tsx import { initializeApp } from 'firebase/app'; import { initializeUI, requireDisplayName } from '@firebase-oss/ui-core'; import { FirebaseUIProvider } from '@firebase-oss/ui-react'; import '@firebase-oss/ui-styles/dist.min.css'; const app = initializeApp({ /* Firebase config */ }); const ui = initializeUI({ app, behaviors: [requireDisplayName()] }); export default function App() { return ( <FirebaseUIProvider ui={ui} policies={{ termsOfServiceUrl: 'https://example.com/terms', privacyPolicyUrl: 'https://example.com/privacy', onNavigate: (url) => router.push(url), }} > <MyRoutes /> </FirebaseUIProvider> ); } ``` --- ### `SignInAuthScreen` — Full email/password sign-in screen (React) Opinionated full-page sign-in card. Automatically shows the `MultiFactorAuthAssertionScreen` if an MFA challenge is triggered. ```tsx import { useState } from 'react'; import type { User } from 'firebase/auth'; import { SignInAuthScreen, GoogleSignInButton, OAuthButton } from '@firebase-oss/ui-react'; import { OAuthProvider } from 'firebase/auth'; function SignInPage() { const [route, setRoute] = useState<'sign-in' | 'sign-up' | 'forgot-password'>('sign-in'); return ( <SignInAuthScreen onSignIn={(user: User) => console.log('Signed in:', user.email)} onSignUpClick={() => setRoute('sign-up')} onForgotPasswordClick={() => setRoute('forgot-password')} > {/* OAuth children appear below a divider */} <GoogleSignInButton themed onSignIn={(cred) => console.log(cred.user.uid)} /> <OAuthButton provider={new OAuthProvider('oidc.my-provider')} themed> Sign in with My Provider </OAuthButton> </SignInAuthScreen> ); } ``` --- ### `SignUpAuthScreen` — Full email/password sign-up screen (React) ```tsx import { SignUpAuthScreen } from '@firebase-oss/ui-react'; import type { User } from 'firebase/auth'; function SignUpPage() { return ( <SignUpAuthScreen onSignUp={(user: User) => { console.log('Account created, UID:', user.uid); router.push('/dashboard'); }} onSignInClick={() => router.push('/sign-in')} /> ); } ``` --- ### `SignInAuthForm` / `SignUpAuthForm` — Unstyled form components (React) Forms fill the width of their container and contain only functional UI without the wrapping card, for embedding in existing layouts. ```tsx import { SignInAuthForm, SignUpAuthForm } from '@firebase-oss/ui-react'; import type { UserCredential } from 'firebase/auth'; function ExistingLoginPage() { return ( <div className="my-existing-layout"> <h1>Welcome Back</h1> <SignInAuthForm onSignIn={(cred: UserCredential) => router.push('/home')} onForgotPasswordClick={() => router.push('/forgot-password')} onSignUpClick={() => router.push('/sign-up')} /> </div> ); } function ExistingSignUpPage() { return ( <div className="my-existing-layout"> <SignUpAuthForm onSignUp={(cred: UserCredential) => router.push('/onboarding')} onSignInClick={() => router.push('/sign-in')} /> </div> ); } ``` --- ### `OAuthScreen` / `OAuthButton` — OAuth provider sign-in screen and buttons (React) ```tsx import { OAuthScreen, GoogleSignInButton, AppleSignInButton, GitHubSignInButton, FacebookSignInButton, MicrosoftSignInButton, TwitterSignInButton, OAuthButton, } from '@firebase-oss/ui-react'; import { OAuthProvider } from 'firebase/auth'; import type { User, UserCredential } from 'firebase/auth'; function OAuthSignInPage() { return ( <OAuthScreen onSignIn={(user: User) => router.push('/dashboard')}> <GoogleSignInButton themed /> <AppleSignInButton themed /> <GitHubSignInButton onSignIn={(cred: UserCredential) => console.log(cred)} /> <FacebookSignInButton /> <MicrosoftSignInButton /> <TwitterSignInButton /> {/* Custom OIDC provider */} <OAuthButton provider={new OAuthProvider('oidc.my-provider')} themed="true" onSignIn={(cred) => console.log('Custom OIDC signed in')} > Sign in with Corporate SSO </OAuthButton> </OAuthScreen> ); } ``` --- ### `PhoneAuthScreen` / `PhoneAuthForm` — Phone authentication (React) Handles the full two-step SMS flow (enter number → enter code) including reCAPTCHA and country selector. ```tsx import { PhoneAuthScreen, PhoneAuthForm } from '@firebase-oss/ui-react'; import type { User, UserCredential } from 'firebase/auth'; // Full screen version function PhoneSignInPage() { return ( <PhoneAuthScreen onSignIn={(user: User) => { console.log('Phone auth complete:', user.phoneNumber); router.push('/dashboard'); }} /> ); } // Form-only version for custom layout function CustomPhonePage() { return ( <div className="my-layout"> <PhoneAuthForm onSignIn={(cred: UserCredential) => router.push('/home')} /> </div> ); } ``` --- ### `MultiFactorAuthEnrollmentScreen` / `MultiFactorAuthAssertionScreen` — MFA screens (React) ```tsx import { MultiFactorAuthEnrollmentScreen, MultiFactorAuthAssertionScreen, } from '@firebase-oss/ui-react'; // Show enrollment screen after user signs in and wants to add MFA function MfaSetupPage() { return <MultiFactorAuthEnrollmentScreen />; // Renders a choice of TOTP or SMS, then guides through enrollment } // Assertion is shown automatically by Sign-In screens when ui.multiFactorResolver is set, // but can also be rendered manually: function MfaChallengePage() { return <MultiFactorAuthAssertionScreen />; } ``` --- ### `useUI` — Access the FirebaseUI instance in React components ```tsx import { useUI } from '@firebase-oss/ui-react'; function LoadingIndicator() { const ui = useUI(); // ui.state: 'idle' | 'pending' | 'loading' // ui.locale, ui.auth, ui.multiFactorResolver, etc. return ui.state !== 'idle' ? <div className="spinner">Loading...</div> : null; } ``` --- ### `useRedirectError` — Get redirect-flow error message (React) ```tsx import { useRedirectError } from '@firebase-oss/ui-react'; function RedirectErrorBanner() { const error = useRedirectError(); if (!error) return null; return <div className="error-banner">{error}</div>; // e.g. "This account already exists with a different sign-in method." } ``` --- ### `useRecaptchaVerifier` — Manage a reCAPTCHA verifier instance (React) ```tsx import { useRef } from 'react'; import { useRecaptchaVerifier } from '@firebase-oss/ui-react'; import { verifyPhoneNumber } from '@firebase-oss/ui-core'; function CustomPhoneForm() { const ui = useUI(); const recaptchaRef = useRef<HTMLDivElement>(null); const verifier = useRecaptchaVerifier(recaptchaRef); async function handleSubmit(phoneNumber: string) { if (!verifier) return; const verificationId = await verifyPhoneNumber(ui, phoneNumber, verifier); console.log('Verification ID:', verificationId); } return ( <form onSubmit={(e) => { e.preventDefault(); handleSubmit('+14155552671'); }}> <div ref={recaptchaRef} /> <button type="submit" disabled={!verifier}>Send Code</button> </form> ); } ``` --- ### `useOnUserAuthenticated` — React hook to react to authenticated user ```tsx import { useOnUserAuthenticated } from '@firebase-oss/ui-react'; import { useRouter } from 'next/navigation'; import type { User } from 'firebase/auth'; function AuthGate() { const router = useRouter(); useOnUserAuthenticated((user: User) => { // Only fires for non-anonymous users console.log('User authenticated:', user.email); router.push('/dashboard'); }); return <SignInAuthScreen />; } ``` --- ### `ForgotPasswordAuthScreen` / `EmailLinkAuthScreen` — Additional auth screens (React) ```tsx import { ForgotPasswordAuthScreen, EmailLinkAuthScreen } from '@firebase-oss/ui-react'; import type { User } from 'firebase/auth'; function ForgotPasswordPage() { return ( <ForgotPasswordAuthScreen onSendPasswordResetEmail={() => console.log('Reset email sent!')} onBackClick={() => router.push('/sign-in')} /> ); } function EmailLinkPage() { return ( <EmailLinkAuthScreen onSendSignInLinkToEmail={() => console.log('Link sent!')} onSignIn={(user: User) => router.push('/dashboard')} /> ); } ``` --- ## `@firebase-oss/ui-angular` ### `provideFirebaseUI` / `provideFirebaseUIPolicies` — Angular providers Configure FirebaseUI in your Angular application's providers array. ```typescript // app.config.ts import { ApplicationConfig } from '@angular/core'; import { provideFirebaseApp, initializeApp } from '@angular/fire/app'; import { provideAuth, getAuth } from '@angular/fire/auth'; import { initializeUI, requireDisplayName } from '@firebase-oss/ui-core'; import { provideFirebaseUI, provideFirebaseUIPolicies } from '@firebase-oss/ui-angular'; export const appConfig: ApplicationConfig = { providers: [ provideFirebaseApp(() => initializeApp({ /* config */ })), provideAuth(() => getAuth()), provideFirebaseUI((apps) => initializeUI({ app: apps[0], behaviors: [requireDisplayName()], }) ), provideFirebaseUIPolicies(() => ({ termsOfServiceUrl: 'https://example.com/terms', privacyPolicyUrl: 'https://example.com/privacy', })), ], }; ``` --- ### Angular auth screen and form components All screens and forms have Angular equivalents with selector-based usage. ```typescript // sign-in.component.ts import { Component } from '@angular/core'; import { User } from '@angular/fire/auth'; import { Router } from '@angular/router'; import { SignInAuthScreenComponent, GoogleSignInButtonComponent, OAuthScreenComponent, SignUpAuthScreenComponent, ForgotPasswordAuthScreenComponent, EmailLinkAuthScreenComponent, PhoneAuthScreenComponent, } from '@firebase-oss/ui-angular'; @Component({ selector: 'app-sign-in', standalone: true, imports: [SignInAuthScreenComponent, GoogleSignInButtonComponent], template: ` <fui-sign-in-auth-screen (signIn)="onSignIn($event)" (signUp)="router.navigate(['/sign-up'])" > <fui-google-sign-in-button (signIn)="onSignIn($event)" /> </fui-sign-in-auth-screen> `, }) export class SignInComponent { constructor(public router: Router) {} onSignIn(user: User) { this.router.navigate(['/dashboard']); } } ``` ```html <!-- OAuth-only sign-in --> <fui-oauth-screen (onSignIn)="onSignIn($event)"> <fui-google-sign-in-button /> <fui-apple-sign-in-button /> <fui-github-sign-in-button /> </fui-oauth-screen> <!-- Phone auth screen --> <fui-phone-auth-screen (signIn)="onSignIn($event)" /> <!-- Email link screen --> <fui-email-link-auth-screen (emailSent)="showConfirmation()" (signIn)="onSignIn($event)" /> <!-- MFA enrollment --> <fui-multi-factor-auth-enrollment-screen /> <!-- Forgot password --> <fui-forgot-password-auth-screen (passwordSent)="showSuccess()" (backToSignIn)="router.navigate(['/sign-in'])" /> ``` --- ### `injectUI` — Inject reactive FirebaseUI signal (Angular) ```typescript import { Component, computed } from '@angular/core'; import { injectUI } from '@firebase-oss/ui-angular'; @Component({ selector: 'app-loading', template: ` <div *ngIf="isPending()">Loading...</div> <div *ngIf="mfaRequired()">MFA required!</div> `, }) export class LoadingComponent { private ui = injectUI(); isPending = computed(() => this.ui().state !== 'idle'); mfaRequired = computed(() => !!this.ui().multiFactorResolver); } ``` --- ### `injectUserAuthenticated` — React to authenticated user (Angular) ```typescript import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { User } from '@angular/fire/auth'; import { injectUserAuthenticated } from '@firebase-oss/ui-angular'; @Component({ selector: 'app-auth-gate', template: `<fui-sign-in-auth-screen />` }) export class AuthGateComponent { constructor(router: Router) { injectUserAuthenticated((user: User) => { // Only fires for non-anonymous users router.navigate(['/dashboard']); }); } } ``` --- ### `injectRecaptchaVerifier` — Angular reCAPTCHA verifier signal ```typescript import { Component, ElementRef, ViewChild, afterNextRender } from '@angular/core'; import { injectRecaptchaVerifier, injectUI } from '@firebase-oss/ui-angular'; import { verifyPhoneNumber } from '@firebase-oss/ui-core'; @Component({ selector: 'app-custom-phone', template: ` <div #recaptchaContainer></div> <button [disabled]="!recaptchaReady()" (click)="sendCode()">Send SMS</button> `, }) export class CustomPhoneComponent { @ViewChild('recaptchaContainer') recaptchaContainer!: ElementRef<HTMLDivElement>; private ui = injectUI(); verifier = injectRecaptchaVerifier(() => this.recaptchaContainer); recaptchaReady = this.verifier.renderCompleted; async sendCode() { const v = this.verifier(); if (!v) return; const verificationId = await verifyPhoneNumber(this.ui(), '+14155552671', v); console.log('Verification ID:', verificationId); } } ``` --- ### `injectTranslation` — Reactive translation signal (Angular) ```typescript import { Component } from '@angular/core'; import { injectTranslation } from '@firebase-oss/ui-angular'; @Component({ selector: 'app-labels', template: `<button>{{ signInLabel() }}</button>`, }) export class LabelsComponent { signInLabel = injectTranslation('labels', 'signIn'); // Automatically updates when locale changes errorText = injectTranslation('errors', 'userNotFound'); } ``` --- ### `injectCountries` / `injectDefaultCountry` — Country data signals (Angular) ```typescript import { Component } from '@angular/core'; import { injectCountries, injectDefaultCountry } from '@firebase-oss/ui-angular'; @Component({ selector: 'app-country-picker', template: ` <p>Default: {{ defaultCountry().emoji }} {{ defaultCountry().dialCode }}</p> <option *ngFor="let c of countries()" [value]="c.code"> {{ c.emoji }} {{ c.name }} ({{ c.dialCode }}) </option> `, }) export class CountryPickerComponent { countries = injectCountries(); defaultCountry = injectDefaultCountry(); } ``` --- ### `injectRedirectError` — Redirect error signal (Angular) ```typescript import { Component } from '@angular/core'; import { injectRedirectError } from '@firebase-oss/ui-angular'; @Component({ selector: 'app-error-banner', template: `<div *ngIf="redirectError()" class="error">{{ redirectError() }}</div>`, }) export class ErrorBannerComponent { redirectError = injectRedirectError(); } ``` --- ## Summary FirebaseUI for Web v7 covers the full authentication lifecycle for both React and Angular applications: from simple email/password and OAuth sign-in flows to advanced scenarios like passwordless email link, phone SMS, Google One Tap, and multi-factor authentication (SMS + TOTP). The library's dual-layer API (Screens for rapid prototyping, Forms for custom layouts, and raw `@firebase-oss/ui-core` functions for headless/custom-framework usage) means it scales from a five-line drop-in to a completely white-label experience. The behavior system enables powerful cross-cutting concerns — anonymous user upgrade, credential conflict resolution, and custom reCAPTCHA configuration — to be activated declaratively without modifying component code. Integration follows a consistent pattern across frameworks: (1) call `initializeUI` with a Firebase app and optional behaviors to get a reactive store, (2) wrap the app with the framework provider (`FirebaseUIProvider` in React or `provideFirebaseUI` in Angular), (3) drop in the desired Screen or Form components. For Shadcn users, a registry-based approach is provided at `fir-ui-shadcn-registry.web.app` instead of npm packages. For unsupported frameworks (Svelte, SolidJS, Vue), the headless `@firebase-oss/ui-core` package exposes all auth functions and Zod schemas, enabling teams to build fully custom UIs while benefiting from the automatic error handling, MFA capture, credential linking, and localization infrastructure the library provides.