diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3eddc3bd..ee2c87f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: node-version: - - 12.x + - 14.x steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 diff --git a/README.md b/README.md index 8b6f50ee..b45ac156 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository holds code snippets used in Web documentation on [firebase.google.com](https://firebase.google.com/docs/). -These snippets are part of our documentation and best read in the context of a documentation page rather than used directly. If you're looking to get started with the Firebase Web SDK the best place to start is [quicstart-web](https://github.com/firebase/quickstart-web). +These snippets are part of our documentation and best read in the context of a documentation page rather than used directly. If you're looking to get started with the Firebase Web SDK the best place to start is [quickstart-js](https://github.com/firebase/quickstart-js). ## Example diff --git a/analytics-next/index.js b/analytics-next/index.js index a93de88a..2b736cde 100644 --- a/analytics-next/index.js +++ b/analytics-next/index.js @@ -27,8 +27,7 @@ function logEventParams() { const analytics = getAnalytics(); logEvent(analytics, 'select_content', { content_type: 'image', - content_id: 'P12453', - items: [{ name: 'Kittens' }] + content_id: 'P12453' }); // [END analytics_log_event_params] } @@ -50,3 +49,18 @@ function setUserProperties() { setUserProperties(analytics, { favorite_food: 'apples' }); // [END analytics_set_user_properties] } + +function recordScreenView() { + const screenName = ''; + const screenClass = ''; + + // [START analytics_record_screen_view] + const { getAnalytics, logEvent } = require("firebase/analytics"); + + const analytics = getAnalytics(); + logEvent(analytics, 'screen_view', { + firebase_screen: screenName, + firebase_screen_class: screenClass + }); + // [END analytics_record_screen_view] +} diff --git a/analytics-next/package.json b/analytics-next/package.json index 94d9a07e..ee4e36ff 100644 --- a/analytics-next/package.json +++ b/analytics-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/analytics/index.js b/analytics/index.js index f8a0e856..76d2c289 100644 --- a/analytics/index.js +++ b/analytics/index.js @@ -38,3 +38,15 @@ function setUserProperties() { firebase.analytics().setUserProperties({favorite_food: 'apples'}); // [END analytics_set_user_properties] } + +function recordScreenView() { + const screenName = ''; + const screenClass = ''; + + // [START analytics_record_screen_view] + firebase.analytics().logEvent('screen_view', { + firebase_screen: screenName, + firebase_screen_class: screenClass + }); + // [END analytics_record_screen_view] +} diff --git a/analytics/package.json b/analytics/package.json index 78c425e7..b344a8a6 100644 --- a/analytics/package.json +++ b/analytics/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/appcheck-next/package.json b/appcheck-next/package.json index 9a7a71bb..e863723e 100644 --- a/appcheck-next/package.json +++ b/appcheck-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/appcheck/package.json b/appcheck/package.json index 7208eddf..d9d819fa 100644 --- a/appcheck/package.json +++ b/appcheck/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/auth-next/apple.js b/auth-next/apple.js index 29a33dea..2777a085 100644 --- a/auth-next/apple.js +++ b/auth-next/apple.js @@ -38,6 +38,7 @@ function appleSignInPopup(provider) { const accessToken = credential.accessToken; const idToken = credential.idToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -45,7 +46,7 @@ function appleSignInPopup(provider) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); @@ -85,7 +86,7 @@ function appleSignInRedirectResult() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); @@ -123,7 +124,7 @@ function appleReauthenticatePopup() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); @@ -169,7 +170,7 @@ function appleNonceNode() { crypto.randomFillSync(buf); nonce = decoder.write(buf); } - return nonce.substr(0, length); + return nonce.slice(0, length); }; const unhashedNonce = generateNonce(10); diff --git a/auth-next/cordova.js b/auth-next/cordova.js index 1823b33c..ff91dfcc 100644 --- a/auth-next/cordova.js +++ b/auth-next/cordova.js @@ -5,7 +5,7 @@ function createGoogleProvider() { // [START auth_create_google_provider] - const { GoogleAuthProvider } = require("firebase/auth"); + const { GoogleAuthProvider } = require("firebase/auth/cordova"); const provider = new GoogleAuthProvider(); // [END auth_create_google_provider] @@ -13,7 +13,7 @@ function createGoogleProvider() { function cordovaSignInRedirect() { // [START auth_cordova_sign_in_redirect] - const { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } = require("firebase/auth"); + const { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } = require("firebase/auth/cordova"); const auth = getAuth(); signInWithRedirect(auth, new GoogleAuthProvider()) @@ -40,7 +40,7 @@ function cordovaSignInRedirect() { function cordovaRedirectResult() { // [START auth_cordova_redirect_result] - const { getAuth, getRedirectResult, GoogleAuthProvider } = require("firebase/auth"); + const { getAuth, getRedirectResult, GoogleAuthProvider } = require("firebase/auth/cordova"); const auth = getAuth(); getRedirectResult(auth) diff --git a/auth-next/custom-dependencies.js b/auth-next/custom-dependencies.js new file mode 100644 index 00000000..209b6767 --- /dev/null +++ b/auth-next/custom-dependencies.js @@ -0,0 +1,58 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +// Docs: https://source.corp.google.com/piper///depot/google3/third_party/devsite/firebase/en/docs/auth/web/custom-dependencies.md + +function getAuthEquivalent() { + // [START auth_get_auth_equivalent] + const {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, browserSessionPersistence, indexedDBLocalPersistence} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence], + popupRedirectResolver: browserPopupRedirectResolver, + }); + // [END auth_get_auth_equivalent] +} + +function onlyBrowserLocal() { + // [START auth_only_browser_local] + const {initializeAuth, browserLocalPersistence} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: browserLocalPersistence, + // No popupRedirectResolver defined + }); + // [END auth_only_browser_local] +} + +function onlyIndexedDB() { + // [START auth_only_indexed_db] + const {initializeAuth, indexedDBLocalPersistence} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: indexedDBLocalPersistence, + // No popupRedirectResolver defined + }); + // [END auth_only_indexed_db] +} + +function signInRedirectManualDeps() { + // [START auth_sign_in_redirect_manual_deps] + const {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, indexedDBLocalPersistence, signInWithRedirect, GoogleAuthProvider} = require("firebase/auth"); + const {initializeApp} = require("firebase/app"); + + const app = initializeApp({/** Your app config */}); + const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence], + }); + + // Later + signInWithRedirect(auth, new GoogleAuthProvider(), browserPopupRedirectResolver); + // [END auth_sign_in_redirect_manual_deps] +} \ No newline at end of file diff --git a/auth-next/custom-email-handler.js b/auth-next/custom-email-handler.js index 728baff8..5fcc1f71 100644 --- a/auth-next/custom-email-handler.js +++ b/auth-next/custom-email-handler.js @@ -28,8 +28,8 @@ function handleUserManagementQueryParams() { // Configure the Firebase SDK. // This is the minimum configuration required for the API to be used. const config = { - 'apiKey': "YOU_API_KEY" // Copy this key from the web initialization - // snippet found in the Firebase console. + 'apiKey': "YOUR_API_KEY" // Copy this key from the web initialization + // snippet found in the Firebase console. }; const app = initializeApp(config); const auth = getAuth(app); diff --git a/auth-next/email-link-auth.js b/auth-next/email-link-auth.js index 59ea2115..fde67663 100644 --- a/auth-next/email-link-auth.js +++ b/auth-next/email-link-auth.js @@ -19,7 +19,8 @@ function emailLinkActionCodeSettings() { installApp: true, minimumVersion: '12' }, - dynamicLinkDomain: 'example.page.link' + // The domain must be configured in Firebase Hosting and owned by the project. + linkDomain: 'custom-domain.com' }; // [END auth_email_link_actioncode_settings] } @@ -68,11 +69,13 @@ function emailLinkComplete() { .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); - // You can access the new user via result.user - // Additional user info profile not available via: - // result.additionalUserInfo.profile == null + // You can access the new user by importing getAdditionalUserInfo + // and calling it with result: + // getAdditionalUserInfo(result) + // You can access the user's profile via: + // getAdditionalUserInfo(result)?.profile // You can check if the user is new or existing: - // result.additionalUserInfo.isNewUser + // getAdditionalUserInfo(result)?.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code diff --git a/auth-next/email.js b/auth-next/email.js index b00551c8..26391f81 100644 --- a/auth-next/email.js +++ b/auth-next/email.js @@ -32,7 +32,7 @@ function signUpWithEmailPassword() { const auth = getAuth(); createUserWithEmailAndPassword(auth, email, password) .then((userCredential) => { - // Signed in + // Signed up const user = userCredential.user; // ... }) diff --git a/auth-next/emulator-suite.js b/auth-next/emulator-suite.js index 66507de3..13b1ba95 100644 --- a/auth-next/emulator-suite.js +++ b/auth-next/emulator-suite.js @@ -6,7 +6,7 @@ function emulatorConnect() { const { getAuth, connectAuthEmulator } = require("firebase/auth"); const auth = getAuth(); - connectAuthEmulator(auth, "http://localhost:9099"); + connectAuthEmulator(auth, "http://127.0.0.1:9099"); // [END auth_emulator_connect] } diff --git a/auth-next/facebook.js b/auth-next/facebook.js index 4b61f4be..3c6feb8a 100644 --- a/auth-next/facebook.js +++ b/auth-next/facebook.js @@ -33,6 +33,7 @@ function facebookSignInPopup(provider) { const credential = FacebookAuthProvider.credentialFromResult(result); const accessToken = credential.accessToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -40,7 +41,7 @@ function facebookSignInPopup(provider) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); @@ -61,12 +62,14 @@ function facebookSignInRedirectResult() { const token = credential.accessToken; const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... @@ -102,7 +105,7 @@ function checkLoginState_wrapper() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... @@ -156,10 +159,19 @@ function authWithCredential(credential) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... }); // [END auth_facebook_signin_credential] } + +function facebookProviderCredential(accessToken) { + // [START auth_facebook_provider_credential] + const { FacebookAuthProvider } = require("firebase/auth"); + + const credential = FacebookAuthProvider.credential(accessToken); + // [END auth_facebook_provider_credential] +} + diff --git a/auth-next/github.js b/auth-next/github.js index 941a9047..4c128721 100644 --- a/auth-next/github.js +++ b/auth-next/github.js @@ -40,13 +40,14 @@ function githubSignInPopup(provider) { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... @@ -70,12 +71,14 @@ function githubSignInRedirectResult() { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... diff --git a/auth-next/google-signin.js b/auth-next/google-signin.js index 78b79a61..025eebd6 100644 --- a/auth-next/google-signin.js +++ b/auth-next/google-signin.js @@ -33,13 +33,14 @@ function googleSignInPopup(provider) { const token = credential.accessToken; // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -60,12 +61,14 @@ function googleSignInRedirectResult() { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -87,7 +90,7 @@ function googleBuildAndSignIn(id_token) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -123,7 +126,7 @@ function onSignIn_wrapper() { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... @@ -157,4 +160,13 @@ function isUserEqual_wrapper() { // [END auth_google_checksameuser] } +function googleProviderCredential(idToken) { + // [START auth_google_provider_credential] + const { GoogleAuthProvider } = require("firebase/auth"); + + const credential = GoogleAuthProvider.credential(idToken); + // [END auth_google_provider_credential] +} + + diff --git a/auth-next/index.js b/auth-next/index.js index 73d33219..04ac7d03 100644 --- a/auth-next/index.js +++ b/auth-next/index.js @@ -26,7 +26,7 @@ function makeFacebookCredential(response) { function makeEmailCredential(email, password) { // [START auth_make_email_credential] const { EmailAuthProvider } = require("firebase/auth"); - + const credential = EmailAuthProvider.credential(email, password); // [END auth_make_email_credential] } @@ -52,7 +52,7 @@ function authStateListener() { onAuthStateChanged(auth, (user) => { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/v8/firebase.User const uid = user.uid; // ... } else { @@ -72,7 +72,7 @@ function currentUser() { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/v8/firebase.User // ... } else { // No user is signed in. @@ -87,7 +87,7 @@ function setLanguageCode() { const auth = getAuth(); auth.languageCode = 'it'; // To apply the default browser preference instead of explicitly setting it. - // firebase.auth().useDeviceLanguage(); + // auth.useDeviceLanguage(); // [END auth_set_language_code] } @@ -107,7 +107,7 @@ function authWithCredential(credential) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // ... }); // [END auth_signin_credential] @@ -121,3 +121,17 @@ function signInRedirect(provider) { signInWithRedirect(auth, provider); // [END auth_signin_redirect] } + +function initializeWithCustomDomain() { + // [START auth_init_custom_domain] + const { initializeApp } = require("firebase/app"); + + const firebaseConfig = { + apiKey: "...", + // By default, authDomain is '[YOUR_APP].firebaseapp.com'. + // You may replace it with a custom domain. + authDomain: '[YOUR_CUSTOM_DOMAIN]' + }; + const firebaseApp = initializeApp(firebaseConfig); + // [END auth_init_custom_domain] +} diff --git a/auth-next/link-multiple-accounts.js b/auth-next/link-multiple-accounts.js index 34c0db58..1938aafc 100644 --- a/auth-next/link-multiple-accounts.js +++ b/auth-next/link-multiple-accounts.js @@ -182,3 +182,61 @@ function unlink(providerId) { }); // [END auth_unlink_provider] } + +function accountExistsPopup(auth, facebookProvider, goToApp, promptUserForPassword, promptUserForSignInMethod, getProviderForProviderId) { + // [START account_exists_popup] + const { signInWithPopup, signInWithEmailAndPassword, linkWithCredential } = require("firebase/auth"); + + // User tries to sign in with Facebook. + signInWithPopup(auth, facebookProvider).catch((error) => { + // User's email already exists. + if (error.code === 'auth/account-exists-with-different-credential') { + // The pending Facebook credential. + const pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + + // Present the user with a list of providers they might have + // used to create the original account. + // Then, ask the user to sign in with the existing provider. + const method = promptUserForSignInMethod(); + + if (method === 'password') { + // TODO: Ask the user for their password. + // In real scenario, you should handle this asynchronously. + const password = promptUserForPassword(); + signInWithEmailAndPassword(auth, email, password).then((result) => { + return linkWithCredential(result.user, pendingCred); + }).then(() => { + // Facebook account successfully linked to the existing user. + goToApp(); + }); + return; + } + + // All other cases are external providers. + // Construct provider object for that provider. + // TODO: Implement getProviderForProviderId. + const provider = getProviderForProviderId(method); + // At this point, you should let the user know that they already have an + // account with a different provider, and validate they want to sign in + // with the new provider. + // Note: Browsers usually block popups triggered asynchronously, so in + // real app, you should ask the user to click on a "Continue" button + // that will trigger signInWithPopup(). + signInWithPopup(auth, provider).then((result) => { + // Note: Identity Platform doesn't control the provider's sign-in + // flow, so it's possible for the user to sign in with an account + // with a different email from the first one. + + // Link the Facebook credential. We have access to the pending + // credential, so we can directly call the link method. + linkWithCredential(result.user, pendingCred).then((userCred) => { + // Success. + goToApp(); + }); + }); + } +}); +// [END account_exists_popup] +} diff --git a/auth-next/multi-tenancy.js b/auth-next/multi-tenancy.js new file mode 100644 index 00000000..d7577f34 --- /dev/null +++ b/auth-next/multi-tenancy.js @@ -0,0 +1,347 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function setTenant() { + // [START multitenant_set_tenant] + const { getAuth } = require("firebase/auth"); + const auth = getAuth(); + const tenantId = "TENANT_ID1"; + auth.tenantId = tenantId; + // [END multitenant_set_tenant] +} + +function switchTenantSingleAuth(auth) { + // [START multitenant_switch_tenant] + // One Auth instance + // Switch to tenant1 + auth.tenantId = "TENANT_ID1"; + // Switch to tenant2 + auth.tenantId = "TENANT_ID2"; + // Switch back to project level IdPs + auth.tenantId = null; + // [END multitenant_switch_tenant] +} + +function switchTenantMultiAuth(firebaseConfig1, firebaseConfig2) { + // [START multitenant_switch_tenant_multiinstance] + // Multiple Auth instances + const { initializeApp } = require("firebase/app"); + const { getAuth } = require("firebase/auth"); + const firebaseApp1 = initializeApp(firebaseConfig1, 'app1_for_tenantId1'); + const firebaseApp2 = initializeApp(firebaseConfig2, 'app2_for_tenantId2'); + + const auth1 = getAuth(firebaseApp1); + const auth2 = getAuth(firebaseApp2); + + auth1.tenantId = "TENANT_ID1"; + auth2.tenantId = "TENANT_ID2"; + // [END multitenant_switch_tenant_multiinstance] +} + +function passwordSignInWithTenantDemo(auth, email, password) { + // [START multitenant_signin_password_demo] + const { signInWithEmailAndPassword, onAuthStateChanged } = require("firebase/auth"); + // Switch to TENANT_ID1 + auth.tenantId = 'TENANT_ID1'; + + // Sign in with tenant + signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Switch to 'TENANT_ID2'. + auth.tenantId = 'TENANT_ID2'; + // auth.currentUser still points to the user. + // auth.currentUser.tenantId is 'TENANT_ID1'. + }); + + // You could also get the current user from Auth state observer. + onAuthStateChanged(auth, (user) => { + if (user) { + // User is signed in. + // user.tenantId is set to 'TENANT_ID1'. + } else { + // No user is signed in. + } + }); + // [END multitenant_signin_password_demo] +} + +function signUpWithTenant(auth, email, password) { + // [START multitenant_signup_password] + const { createUserWithEmailAndPassword } = require("firebase/auth"); + auth.tenantId = 'TENANT_ID'; + + createUserWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signup_password] +} + + +function passwordSignInWithTenant(auth, email, password) { + // [START multitenant_signin_password] + const { signInWithEmailAndPassword } = require("firebase/auth"); + auth.tenantId = 'TENANT_ID'; + + signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_password] +} + +function samlSignInPopupTenant(auth, provider) { + // [START multitenant_signin_saml_popup] + const { signInWithPopup } = require("firebase/auth"); + // Switch to TENANT_ID1. + auth.tenantId = 'TENANT_ID1'; + + // Sign-in with popup. + signInWithPopup(auth, provider) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_saml_popup] +} + +function samlSignInRedirectTenant(auth, provider) { + // [START multitenant_signin_saml_redirect] + const { signInWithRedirect, getRedirectResult } = require("firebase/auth"); + // Switch to TENANT_ID1. + auth.tenantId = 'TENANT_ID1'; + + // Sign-in with redirect. + signInWithRedirect(auth, provider); + + // After the user completes sign-in and returns to the app, you can get + // the sign-in result by calling getRedirectResult. However, if they sign out + // and sign in again with an IdP, no tenant is used. + getRedirectResult(auth) + .then((result) => { + // User is signed in. + // The tenant ID available in result.user.tenantId. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_saml_redirect] +} + +function sendSignInLinkToEmailTenant(auth, email, actionCodeSettings) { + // [START multitenant_send_emaillink] + const { sendSignInLinkToEmail } = require("firebase/auth"); + // Switch to TENANT_ID1 + auth.tenantId = 'TENANT_ID1'; + + sendSignInLinkToEmail(auth, email, actionCodeSettings) + .then(() => { + // The link was successfully sent. Inform the user. + // Save the email locally so you don't need to ask the user for it again + // if they open the link on the same device. + window.localStorage.setItem('emailForSignIn', email); + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_send_emaillink] +} + +function signInWithEmailLinkTenant(auth) { + // [START multitenant_signin_emaillink] + const { isSignInWithEmailLink, parseActionCodeURL, signInWithEmailLink } = require("firebase/auth"); + if (isSignInWithEmailLink(auth, window.location.href)) { + const actionCodeUrl = parseActionCodeURL(window.location.href); + if (actionCodeUrl.tenantId) { + auth.tenantId = actionCodeUrl.tenantId; + } + let email = window.localStorage.getItem('emailForSignIn'); + if (!email) { + // User opened the link on a different device. To prevent session fixation + // attacks, ask the user to provide the associated email again. For example: + email = window.prompt('Please provide your email for confirmation'); + } + // The client SDK will parse the code from the link for you. + signInWithEmailLink(auth, email, window.location.href) + .then((result) => { + // User is signed in. + // tenant ID available in result.user.tenantId. + // Clear email from storage. + window.localStorage.removeItem('emailForSignIn'); + }); + } + // [END multitenant_signin_emaillink] +} + +// Same as the code in auth/ since this is the admin SDK. +function createCustomTokenTenant(admin, uid) { + // [START multitenant_create_custom_token] + // Ensure you're using a tenant-aware auth instance + const tenantManager = admin.auth().tenantManager(); + const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); + + // Create a custom token in the usual manner + tenantAuth.createCustomToken(uid) + .then((customToken) => { + // Send token back to client + }) + .catch((error) => { + console.log('Error creating custom token:', error); + }); + // [END multitenant_create_custom_token] +} + +function signInWithCustomTokenTenant(auth, token) { + // [START multitenant_signin_custom_token] + const { signInWithCustomToken } = require("firebase/auth"); + auth.tenantId = 'TENANT_ID1'; + + signInWithCustomToken(auth, token) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_signin_custom_token] +} + +function linkAccountTenant(auth, provider, email, password) { + // [START multitenant_account_linking] + const { signInWithPopup, EmailAuthProvider, linkWithCredential, SAMLAuthProvider, signInWithCredential } = require("firebase/auth"); + // Switch to TENANT_ID1 + auth.tenantId = 'TENANT_ID1'; + + // Sign-in with popup + signInWithPopup(auth, provider) + .then((userCredential) => { + // Existing user with e.g. SAML provider. + const prevUser = userCredential.user; + const emailCredential = + EmailAuthProvider.credential(email, password); + return linkWithCredential(prevUser, emailCredential) + .then((linkResult) => { + // Sign in with the newly linked credential + const linkCredential = SAMLAuthProvider.credentialFromResult(linkResult); + return signInWithCredential(auth, linkCredential); + }) + .then((signInResult) => { + // Handle sign in of merged user + // ... + }); + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END multitenant_account_linking] +} + +function accountExistsPopupTenant(auth, samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_popup] + const { signInWithPopup, fetchSignInMethodsForEmail, linkWithCredential } = require("firebase/auth"); + // Step 1. + // User tries to sign in to the SAML provider in that tenant. + auth.tenantId = 'TENANT_ID'; + signInWithPopup(auth, samlProvider) + .catch((error) => { + // An error happened. + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + // The pending SAML credential. + const pendingCred = error.credential; + // The credential's tenantId if needed: error.tenantId + // The provider account's email address. + const email = error.customData.email; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(email, auth) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithPopup(auth, googleProvider) + .then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + } + }); + } + }); + // [END multitenant_account_exists_popup] +} + +function accountExistsRedirectTenant(auth, samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_redirect] + const { signInWithRedirect, getRedirectResult, fetchSignInMethodsForEmail, linkWithCredential } = require("firebase/auth"); + // Step 1. + // User tries to sign in to SAML provider. + auth.tenantId = 'TENANT_ID'; + signInWithRedirect(auth, samlProvider); + var pendingCred; + // Redirect back from SAML IDP. auth.tenantId is null after redirecting. + getRedirectResult(auth).catch((error) => { + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + const tenantId = error.tenantId; + // The pending SAML credential. + pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + // Need to set the tenant ID again as the page was reloaded and the + // previous setting was reset. + auth.tenantId = tenantId; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(auth, email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithRedirect(auth, googleProvider); + } + }); + } + }); + + // Redirect back from Google. auth.tenantId is null after redirecting. + getRedirectResult(auth).then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + // result.user.tenantId is 'TENANT_ID'. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + // [END multitenant_account_exists_redirect] +} \ No newline at end of file diff --git a/auth-next/oidc.js b/auth-next/oidc.js new file mode 100644 index 00000000..dae69fe9 --- /dev/null +++ b/auth-next/oidc.js @@ -0,0 +1,96 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function oidcProvider() { + // [START auth_oidc_provider_create] + const { OAuthProvider } = require("firebase/auth"); + + const provider = new OAuthProvider("oidc.myProvider"); + // [END auth_oidc_provider_create] +} + +function oidcSignInPopup(provider) { + // [START auth_oidc_signin_popup] + const { getAuth, signInWithPopup, OAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_oidc_signin_popup] +} + +function oidcSignInRedirect(provider) { + // [START auth_oidc_signin_redirect] + const { getAuth, signInWithRedirect } = require("firebase/auth"); + + const auth = getAuth(); + signInWithRedirect(auth, provider); + // [END auth_oidc_signin_redirect] +} + +function oidcSignInRedirectResult(provider) { + // [START auth_oidc_signin_redirect_result] + const { getAuth, getRedirectResult, OAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + getRedirectResult(auth) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_oidc_signin_redirect_result] +} + +function oidcDirectSignIn(provider, oidcIdToken) { + // [START auth_oidc_direct_sign_in] + const { getAuth, OAuthProvider, signInWithCredential } = require("firebase/auth"); + + const auth = getAuth(); + const credential = provider.credential({ + idToken: oidcIdToken, + }); + signInWithCredential(auth, credential) + .then((result) => { + // User is signed in. + const newCredential = OAuthProvider.credentialFromResult(result); + // This gives you a new access token for the OIDC provider. You can use it to directly interact with that provider. + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_oidc_direct_sign_in] +} \ No newline at end of file diff --git a/auth-next/package.json b/auth-next/package.json index 68d38869..8d43bad1 100644 --- a/auth-next/package.json +++ b/auth-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/auth-next/phone-auth.js b/auth-next/phone-auth.js index cd894c64..99492f99 100644 --- a/auth-next/phone-auth.js +++ b/auth-next/phone-auth.js @@ -15,13 +15,13 @@ function recaptchaVerifierInvisible() { const { getAuth, RecaptchaVerifier } = require("firebase/auth"); const auth = getAuth(); - window.recaptchaVerifier = new RecaptchaVerifier('sign-in-button', { + window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', { 'size': 'invisible', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. onSignInSubmit(); } - }, auth); + }); // [END auth_phone_recaptcha_verifier_invisible] } @@ -30,7 +30,7 @@ function recaptchaVerifierVisible() { const { getAuth, RecaptchaVerifier } = require("firebase/auth"); const auth = getAuth(); - window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', { + window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', { 'size': 'normal', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. @@ -40,7 +40,7 @@ function recaptchaVerifierVisible() { // Response expired. Ask user to solve reCAPTCHA again. // ... } - }, auth); + }); // [END auth_phone_recaptcha_verifier_visible] } @@ -49,7 +49,7 @@ function recaptchaVerifierSimple() { const { getAuth, RecaptchaVerifier } = require("firebase/auth"); const auth = getAuth(); - window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {}, auth); + window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {}); // [END auth_phone_recaptcha_verifier_simple] } diff --git a/auth-next/saml.js b/auth-next/saml.js new file mode 100644 index 00000000..cdecce56 --- /dev/null +++ b/auth-next/saml.js @@ -0,0 +1,68 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function samlProvider() { + // [START auth_saml_provider_create] + const { SAMLAuthProvider } = require("firebase/auth"); + + const provider = new SAMLAuthProvider("saml.myProvider"); + // [END auth_saml_provider_create] +} + +function samlSignInPopup(provider) { + // [START auth_saml_signin_popup] + const { getAuth, signInWithPopup, SAMLAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_saml_signin_popup] +} + +function samlSignInRedirect(provider) { + // [START auth_saml_signin_redirect] + const { getAuth, signInWithRedirect } = require("firebase/auth"); + + const auth = getAuth(); + signInWithRedirect(auth, provider); + // [END auth_saml_signin_redirect] +} + +function samlSignInRedirectResult(provider) { + // [START auth_saml_signin_redirect_result] + const { getAuth, getRedirectResult, SAMLAuthProvider } = require("firebase/auth"); + + const auth = getAuth(); + getRedirectResult(auth) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); + // [END auth_saml_signin_redirect_result] +} \ No newline at end of file diff --git a/auth-next/twitter.js b/auth-next/twitter.js index 8024bbe5..f96e574b 100644 --- a/auth-next/twitter.js +++ b/auth-next/twitter.js @@ -30,13 +30,14 @@ function twitterSignInPopup(provider) { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... @@ -60,12 +61,14 @@ function twitterSignInRedirectResult() { // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... @@ -73,3 +76,10 @@ function twitterSignInRedirectResult() { // [END auth_twitter_signin_redirect_result] } +function twitterProviderCredential(accessToken, secret) { + // [START auth_twitter_provider_credential] + const { TwitterAuthProvider } = require("firebase/auth"); + + const credential = TwitterAuthProvider.credential(accessToken, secret); + // [END auth_twitter_provider_credential] +} \ No newline at end of file diff --git a/auth/apple.js b/auth/apple.js index ad65ef08..00e2598e 100644 --- a/auth/apple.js +++ b/auth/apple.js @@ -40,7 +40,8 @@ function appleSignInPopup(provider) { var accessToken = credential.accessToken; var idToken = credential.idToken; - // ... + // IdP data available using getAdditionalUserInfo(result) + // ... }) .catch((error) => { // Handle Errors here. @@ -77,6 +78,7 @@ function appleSignInRedirectResult() { var accessToken = credential.accessToken; var idToken = credential.idToken; + // IdP data available in result.additionalUserInfo.profile. // ... } // The signed-in user info. @@ -117,7 +119,8 @@ function appleReauthenticatePopup() { var accessToken = credential.accessToken; var idToken = credential.idToken; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }) .catch((error) => { // Handle Errors here. @@ -170,7 +173,7 @@ function appleNonceNode() { crypto.randomFillSync(buf); nonce = decoder.write(buf); } - return nonce.substr(0, length); + return nonce.slice(0, length); }; const unhashedNonce = generateNonce(10); diff --git a/auth/emulator-suite.js b/auth/emulator-suite.js index b14a72db..b0f815e2 100644 --- a/auth/emulator-suite.js +++ b/auth/emulator-suite.js @@ -4,7 +4,7 @@ import "firebase/auth"; function emulatorConnect() { // [START auth_emulator_connect] const auth = firebase.auth(); - auth.useEmulator("http://localhost:9099"); + auth.useEmulator("http://127.0.0.1:9099"); // [END auth_emulator_connect] } diff --git a/auth/facebook.js b/auth/facebook.js index 3e5c5b14..75e99d43 100644 --- a/auth/facebook.js +++ b/auth/facebook.js @@ -31,6 +31,8 @@ function facebookSignInPopup(provider) { // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... // This gives you a Facebook Access Token. You can use it to access the Facebook API. var accessToken = credential.accessToken; @@ -66,6 +68,8 @@ function facebookSignInRedirectResult() { } // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -151,3 +155,9 @@ function authWithCredential(credential) { }); // [END auth_facebook_signin_credential] } + +function facebookProviderCredential(accessToken) { + // [START auth_facebook_provider_credential] + var credential = firebase.auth.FacebookAuthProvider.credential(accessToken); + // [END auth_facebook_provider_credential] +} diff --git a/auth/github.js b/auth/github.js index 6ae1e531..8ae9b39c 100644 --- a/auth/github.js +++ b/auth/github.js @@ -40,7 +40,8 @@ function githubSignInPopup(provider) { // The signed-in user info. var user = result.user; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -70,6 +71,8 @@ function githubSignInRedirectResult() { // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; diff --git a/auth/google-signin.js b/auth/google-signin.js index 908a32e1..06a488e4 100644 --- a/auth/google-signin.js +++ b/auth/google-signin.js @@ -34,7 +34,8 @@ function googleSignInPopup(provider) { var token = credential.accessToken; // The signed-in user info. var user = result.user; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -63,6 +64,8 @@ function googleSignInRedirectResult() { } // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -142,3 +145,9 @@ function isUserEqual(googleUser, firebaseUser) { return false; } // [END auth_google_checksameuser] + +function googleProviderCredential(idToken) { + // [START auth_google_provider_credential] + var credential = firebase.auth.GoogleAuthProvider.credential(idToken); + // [END auth_google_provider_credential] +} diff --git a/auth/index.js b/auth/index.js index 6ea5d587..35546aa3 100644 --- a/auth/index.js +++ b/auth/index.js @@ -43,7 +43,7 @@ function authStateListener() { firebase.auth().onAuthStateChanged((user) => { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/v8/firebase.User var uid = user.uid; // ... } else { @@ -60,7 +60,7 @@ function currentUser() { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/v8/firebase.User // ... } else { // No user is signed in. @@ -101,3 +101,14 @@ function signInRedirect(provider) { firebase.auth().signInWithRedirect(provider); // [END auth_signin_redirect] } + +function initializeWithCustomDomain() { + // [START auth_init_custom_domain] + firebase.initializeApp({ + apiKey: '...', + // By default, authDomain is '[YOUR_APP].firebaseapp.com'. + // You may replace it with a custom domain. + authDomain: '[YOUR_CUSTOM_DOMAIN]' + }); + // [END auth_init_custom_domain] +} diff --git a/auth/initialization.txt b/auth/initialization.txt new file mode 100644 index 00000000..bccb0571 --- /dev/null +++ b/auth/initialization.txt @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/auth/link-multiple-accounts.js b/auth/link-multiple-accounts.js index 30f5a2ec..8eed77b8 100644 --- a/auth/link-multiple-accounts.js +++ b/auth/link-multiple-accounts.js @@ -166,3 +166,59 @@ function unlink(providerId) { }); // [END auth_unlink_provider] } + +function accountExistsPopup(facebookProvider, goToApp, promptUserForPassword, promptUserForSignInMethod, getProviderForProviderId) { + // [START account_exists_popup] + // User tries to sign in with Facebook. + auth.signInWithPopup(facebookProvider).catch((error) => { + // User's email already exists. + if (error.code === 'auth/account-exists-with-different-credential') { + // The pending Facebook credential. + const pendingCred = error.credential; + // The provider account's email address. + const email = error.email; + + // Present the user with a list of providers they might have + // used to create the original account. + // Then, ask the user to sign in with the existing provider. + const method = promptUserForSignInMethod(); + + if (method === 'password') { + // TODO: Ask the user for their password. + // In real scenario, you should handle this asynchronously. + const password = promptUserForPassword(); + auth.signInWithEmailAndPassword(email, password).then((result) => { + return result.user.linkWithCredential(pendingCred); + }).then(() => { + // Facebook account successfully linked to the existing user. + goToApp(); + }); + return; + } + + // All other cases are external providers. + // Construct provider object for that provider. + // TODO: Implement getProviderForProviderId. + const provider = getProviderForProviderId(method); + // At this point, you should let the user know that they already have an + // account with a different provider, and validate they want to sign in + // with the new provider. + // Note: Browsers usually block popups triggered asynchronously, so in + // real app, you should ask the user to click on a "Continue" button + // that will trigger signInWithPopup(). + auth.signInWithPopup(provider).then((result) => { + // Note: Identity Platform doesn't control the provider's sign-in + // flow, so it's possible for the user to sign in with an account + // with a different email from the first one. + + // Link the Facebook credential. We have access to the pending + // credential, so we can directly call the link method. + result.user.linkWithCredential(pendingCred).then((userCred) => { + // Success. + goToApp(); + }); + }); + } +}); +// [END account_exists_popup] +} diff --git a/auth/manage.js b/auth/manage.js index 7163ef00..0e1f0e7b 100644 --- a/auth/manage.js +++ b/auth/manage.js @@ -16,7 +16,7 @@ function getUserProfile() { // The user's ID, unique to the Firebase project. Do NOT use // this value to authenticate with your backend server, if - // you have one. Use User.getToken() instead. + // you have one. Use User.getIdToken() instead. const uid = user.uid; } // [END auth_get_user_profile] @@ -144,7 +144,7 @@ function reauthenticateWithCredential() { user.reauthenticateWithCredential(credential).then(() => { // User re-authenticated. }).catch((error) => { - // An error ocurred + // An error occurred // ... }); // [END auth_reauth_with_credential] diff --git a/auth/multi-tenancy.js b/auth/multi-tenancy.js new file mode 100644 index 00000000..8b31e145 --- /dev/null +++ b/auth/multi-tenancy.js @@ -0,0 +1,312 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/auth"; + +function setTenant() { + // [START multitenant_set_tenant] + const tenantId = "TENANT_ID1"; + firebase.auth().tenantId = tenantId; + // [END multitenant_set_tenant] +} + +function switchTenantSingleAuth() { + // [START multitenant_switch_tenant] + // One Auth instance + // Switch to tenant1 + firebase.auth().tenantId = "TENANT_ID1"; + // Switch to tenant2 + firebase.auth().tenantId = "TENANT_ID2"; + // Switch back to project level IdPs + firebase.auth().tenantId = null; + // [END multitenant_switch_tenant] +} + +function switchTenantMultiAuth(config) { + // [START multitenant_switch_tenant_multiinstance] + // Multiple Auth instances + firebase.initializeApp(config, 'app1_for_tenantId1'); + firebase.initializeApp(config, 'app2_for_tenantId2'); + + const auth1 = firebase.app('app1').auth(); + const auth2 = firebase.app('app2').auth(); + + auth1.tenantId = "TENANT_ID1"; + auth2.tenantId = "TENANT_ID2"; + // [END multitenant_switch_tenant_multiinstance] +} + +function passwordSignInWithTenantDemo(email, password) { + // [START multitenant_signin_password_demo] + // Switch to TENANT_ID1 + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign in with tenant + firebase.auth().signInWithEmailAndPassword(email, password) + .then((result) => { + const user = result.user; + // user.tenantId is set to 'TENANT_ID1'. + // Switch to 'TENANT_ID2'. + firebase.auth().tenantId = 'TENANT_ID2'; + // firebase.auth().currentUser still point to the user. + // firebase.auth().currentUser.tenantId is 'TENANT_ID1'. + }); + + // You could also get the current user from Auth state observer. + firebase.auth().onAuthStateChanged((user) => { + if (user) { + // User is signed in. + // user.tenantId is set to 'TENANT_ID1'. + } else { + // No user is signed in. + } + }); + // [END multitenant_signin_password_demo] +} + +function signUpWithTenant(email, password) { + // [START multitenant_signup_password] + firebase.auth().tenantId = 'TENANT_ID'; + + firebase.auth().createUserWithEmailAndPassword(email, password) + .then((result) => { + // result.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle error. + }); + // [END multitenant_signup_password] +} + + +function passwordSignInWithTenant(email, password) { + // [START multitenant_signin_password] + firebase.auth().tenantId = 'TENANT_ID'; + + firebase.auth().signInWithEmailAndPassword(email, password) + .then((result) => { + // result.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle error. + }); + // [END multitenant_signin_password] +} + +function samlSignInPopupTenant(provider) { + // [START multitenant_signin_saml_popup] + // Switch to TENANT_ID1. + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign-in with popup. + firebase.auth().signInWithPopup(provider) + .then((result) => { + // User is signed in. + // tenant ID is available in result.user.tenantId. + // Identity provider data is available in result.additionalUserInfo.profile. + }) + .catch((error) => { + // Handle error. + }); + // [END multitenant_signin_saml_popup] +} + +function samlSignInRedirectTenant(provider) { + // [START multitenant_signin_saml_redirect] + // Switch to TENANT_ID1. + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign-in with redirect. + firebase.auth().signInWithRedirect(provider); + + // After the user completes sign-in and returns to the app, you can get + // the sign-in result by calling getRedirectResult. However, if they sign out + // and sign in again with an IdP, no tenant is used. + firebase.auth().getRedirectResult() + .then((result) => { + // User is signed in. + // The tenant ID available in result.user.tenantId. + // Identity provider data is available in result.additionalUserInfo.profile. + }) + .catch((error) => { + // Handle error. + }); + // [END multitenant_signin_saml_redirect] +} + +function sendSignInLinkToEmailTenant(email, actionCodeSettings) { + // [START multitenant_send_emaillink] + // Switch to TENANT_ID1 + firebase.auth().tenantId = 'TENANT_ID1'; + + firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings) + .then(() => { + // The link was successfully sent. Inform the user. + // Save the email locally so you don't need to ask the user for it again + // if they open the link on the same device. + window.localStorage.setItem('emailForSignIn', email); + }) + .catch((error) => { + // Some error occurred, you can inspect the code: error.code + }); + // [END multitenant_send_emaillink] +} + +function signInWithEmailLinkTenant() { + // [START multitenant_signin_emaillink] + if (firebase.auth().isSignInWithEmailLink(window.location.href)) { + const actionCodeUrl = firebase.auth.ActionCodeURL.parseLink(window.location.href); + if (actionCodeUrl.tenantId) { + firebase.auth().tenantId = actionCodeUrl.tenantId; + } + let email = window.localStorage.getItem('emailForSignIn'); + if (!email) { + // User opened the link on a different device. To prevent session fixation + // attacks, ask the user to provide the associated email again. For example: + email = window.prompt('Please provide your email for confirmation'); + } + firebase.auth().signInWithEmailLink(email, window.location.href) + .then((result) => { + // User is signed in. + // tenant ID available in result.user.tenantId. + }); + } + // [END multitenant_signin_emaillink] +} + +function createCustomTokenTenant(admin, uid) { + // [START multitenant_create_custom_token] + // Ensure you're using a tenant-aware auth instance + const tenantManager = admin.auth().tenantManager(); + const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); + + // Create a custom token in the usual manner + tenantAuth.createCustomToken(uid) + .then((customToken) => { + // Send token back to client + }) + .catch((error) => { + console.log('Error creating custom token:', error); + }); + // [END multitenant_create_custom_token] +} + +function signInWithCustomTokenTenant(token) { + // [START multitenant_signin_custom_token] + firebase.auth().tenantId = 'TENANT_ID1'; + + firebase.auth().signInWithCustomToken(token) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // ... + }); + // [END multitenant_signin_custom_token] +} + +function linkAccountTenant(provider, email, password) { + // [START multitenant_account_linking] + // Switch to TENANT_ID1 + firebase.auth().tenantId = 'TENANT_ID1'; + + // Sign-in with popup + firebase.auth().signInWithPopup(provider) + .then((result) => { + // Existing user with e.g. SAML provider. + const user = result.user; + const emailCredential = + firebase.auth.EmailAuthProvider.credential(email, password); + return user.linkWithCredential(emailCredential); + }) + .then((linkResult) => { + // The user can sign in with both SAML and email/password now. + }); + // [END multitenant_account_linking] +} + +function accountExistsPopupTenant(samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_popup] + // Step 1. + // User tries to sign in to the SAML provider in that tenant. + firebase.auth().tenantId = 'TENANT_ID'; + firebase.auth().signInWithPopup(samlProvider) + .catch((error) => { + // An error happened. + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + // The pending SAML credential. + const pendingCred = error.credential; + // The credential's tenantId if needed: error.tenantId + // The provider account's email address. + const email = error.email; + // Get sign-in methods for this email. + firebase.auth().fetchSignInMethodsForEmail(email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + firebase.auth().signInWithPopup(googleProvider) + .then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + result.user.linkWithCredential(pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + } + }); + } + }); + // [END multitenant_account_exists_popup] +} + +function accountExistsRedirectTenant(samlProvider, googleProvider, goToApp) { + // [START multitenant_account_exists_redirect] + // Step 1. + // User tries to sign in to SAML provider. + firebase.auth().tenantId = 'TENANT_ID'; + firebase.auth().signInWithRedirect(samlProvider); + var pendingCred; + // Redirect back from SAML IDP. auth.tenantId is null after redirecting. + firebase.auth().getRedirectResult().catch((error) => { + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + const tenantId = error.tenantId; + // The pending SAML credential. + pendingCred = error.credential; + // The provider account's email address. + const email = error.email; + // Need to set the tenant ID again as the page was reloaded and the + // previous setting was reset. + firebase.auth().tenantId = tenantId; + // Get sign-in methods for this email. + firebase.auth().fetchSignInMethodsForEmail(email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + firebase.auth().signInWithRedirect(googleProvider); + } + }); + } + }); + + // Redirect back from Google. auth.tenantId is null after redirecting. + firebase.auth().getRedirectResult().then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + // result.user.tenantId is 'TENANT_ID'. + result.user.linkWithCredential(pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + // [END multitenant_account_exists_redirect] +} \ No newline at end of file diff --git a/auth/oidc.js b/auth/oidc.js new file mode 100644 index 00000000..e3a3e01e --- /dev/null +++ b/auth/oidc.js @@ -0,0 +1,68 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/auth"; + +function oidcProvider() { + // [START auth_oidc_provider_create] + const provider = new firebase.auth.OAuthProvider('oidc.myProvider'); + // [END auth_oidc_provider_create] +} + +function oidcSignInPopup(provider) { + // [START auth_oidc_signin_popup] + firebase.auth().signInWithPopup(provider) + .then((result) => { + // User is signed in. + // result.credential is a firebase.auth().OAuthCredential object. + // result.credential.providerId is equal to 'oidc.myProvider'. + // result.credential.idToken is the OIDC provider's ID token. + }) + .catch((error) => { + // Handle error. + }); + // [END auth_oidc_signin_popup] +} + +function oidcSignInRedirect(provider) { + // [START auth_oidc_signin_redirect] + firebase.auth().signInWithRedirect(provider).catch((error) => { + // Handle error. + }); + // [END auth_oidc_signin_redirect] +} + +function oidcSignInRedirectResult(provider) { + // [START auth_oidc_signin_redirect_result] + // On return. + firebase.auth().getRedirectResult() + .then((result) => { + // User is signed in. + // result.credential is a firebase.auth().OAuthCredential object. + // result.credential.providerId is equal to 'oidc.myProvider'. + // result.credential.idToken is the OIDC provider's ID token. + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_oidc_signin_redirect_result] +} + +function oidcDirectSignIn(provider, oidcIdToken) { + // [START auth_oidc_direct_sign_in] + const credential = provider.credential(oidcIdToken, null); + + firebase.auth().signInWithCredential(credential) + .then((result) => { + // User is signed in. + // User now has a odic.myProvider UserInfo in providerData. + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_oidc_direct_sign_in] +} + diff --git a/auth/package.json b/auth/package.json index 95ed84c2..b4b13f01 100644 --- a/auth/package.json +++ b/auth/package.json @@ -6,7 +6,8 @@ }, "license": "Apache 2.0", "dependencies": { - "firebase": "^8.8.1", - "firebaseui": "^4.8.1" + "firebase": "^8.10.0", + "firebase-admin": "^12.0.0", + "firebaseui": "^5.0.0" } } diff --git a/auth/saml.js b/auth/saml.js new file mode 100644 index 00000000..e3a99cde --- /dev/null +++ b/auth/saml.js @@ -0,0 +1,53 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/auth"; + +function samlProvider() { + // [START auth_saml_provider_create] + const provider = new firebase.auth.SAMLAuthProvider('saml.myProvider'); + // [END auth_saml_provider_create] +} + +function samlSignInPopup(provider) { + // [START auth_saml_signin_popup] + firebase.auth().signInWithPopup(provider) + .then((result) => { + // User is signed in. + // Identity provider data available in result.additionalUserInfo.profile, + // or from the user's ID token obtained from result.user.getIdToken() + // as an object in the firebase.sign_in_attributes custom claim + // This is also available from result.user.getIdTokenResult() + // idTokenResult.claims.firebase.sign_in_attributes. + }) + .catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_saml_signin_popup] +} + +function samlSignInRedirect(provider) { + // [START auth_saml_signin_redirect] + firebase.auth().signInWithRedirect(provider); + // [END auth_saml_signin_redirect] +} + +function samlSignInRedirectResult(provider) { + // [START auth_saml_signin_redirect_result] + firebase.auth().getRedirectResult() + .then((result) => { + // User is signed in. + // Provider data available in result.additionalUserInfo.profile, + // or from the user's ID token obtained from result.user.getIdToken() + // as an object in the firebase.sign_in_attributes custom claim + // This is also available from result.user.getIdTokenResult() + // idTokenResult.claims.firebase.sign_in_attributes. + }).catch((error) => { + // Handle / display error. + // ... + }); + // [END auth_saml_signin_redirect_result] +} + diff --git a/auth/service-worker-sessions.js b/auth/service-worker-sessions.js index babbf91e..05791463 100644 --- a/auth/service-worker-sessions.js +++ b/auth/service-worker-sessions.js @@ -162,3 +162,46 @@ function svcSignInEmail(email, password) { }); // [END auth_svc_sign_in_email] } + +function svcRedirectAdmin() { + const app = { use: (a) => {} }; + + // [START auth_svc_admin] + // Server side code. + const admin = require('firebase-admin'); + + // The Firebase Admin SDK is used here to verify the ID token. + admin.initializeApp(); + + function getIdToken(req) { + // Parse the injected ID token from the request header. + const authorizationHeader = req.headers.authorization || ''; + const components = authorizationHeader.split(' '); + return components.length > 1 ? components[1] : ''; + } + + function checkIfSignedIn(url) { + return (req, res, next) => { + if (req.url == url) { + const idToken = getIdToken(req); + // Verify the ID token using the Firebase Admin SDK. + // User already logged in. Redirect to profile page. + admin.auth().verifyIdToken(idToken).then((decodedClaims) => { + // User is authenticated, user claims can be retrieved from + // decodedClaims. + // In this sample code, authenticated users are always redirected to + // the profile page. + res.redirect('/profile'); + }).catch((error) => { + next(); + }); + } else { + next(); + } + }; + } + + // If a user is signed in, redirect to profile page. + app.use(checkIfSignedIn('/')); + // [END auth_svc_admin] +} diff --git a/auth/twitter.js b/auth/twitter.js index b1ca2581..68ed6f35 100644 --- a/auth/twitter.js +++ b/auth/twitter.js @@ -32,7 +32,8 @@ function twitterSignInPopup(provider) { // The signed-in user info. var user = result.user; - // ... + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -64,6 +65,8 @@ function twitterSignInRedirectResult() { // The signed-in user info. var user = result.user; + // IdP data available in result.additionalUserInfo.profile. + // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; @@ -76,3 +79,9 @@ function twitterSignInRedirectResult() { }); // [END auth_twitter_signin_redirect_result] } + +function twitterProviderCredential(accessToken, secret) { + // [START auth_twitter_provider_credential] + var credential = firebase.auth.TwitterAuthProvider.credential(accessToken, secret); + // [END auth_twitter_provider_credential] +} \ No newline at end of file diff --git a/database-next/emulator-suite.js b/database-next/emulator-suite.js index ab86bf9b..f94d3c89 100644 --- a/database-next/emulator-suite.js +++ b/database-next/emulator-suite.js @@ -8,7 +8,7 @@ function onDocumentReady() { const db = getDatabase(); if (location.hostname === "localhost") { // Point to the RTDB emulator running on localhost. - connectDatabaseEmulator(db, "localhost", 9000); + connectDatabaseEmulator(db, "127.0.0.1", 9000); } // [END rtdb_emulator_connect] } diff --git a/database-next/package.json b/database-next/package.json index 1c21a0e6..eb16e2d5 100644 --- a/database-next/package.json +++ b/database-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/database-next/read-and-write.js b/database-next/read-and-write.js index 2cbd5c5b..c06c66b4 100644 --- a/database-next/read-and-write.js +++ b/database-next/read-and-write.js @@ -44,7 +44,7 @@ function socialListenStarCount() { } // [START rtdb_social_listen_star_count] - const { getDatabase, ref, onValue} = require("firebase/database"); + const { getDatabase, ref, onValue } = require("firebase/database"); const db = getDatabase(); const starCountRef = ref(db, 'posts/' + postId + '/starCount'); @@ -74,9 +74,9 @@ function socialSingleValueRead() { } function writeNewPost_wrapped() { + // [START rtdb_social_write_fan_out] const { getDatabase, ref, child, push, update } = require("firebase/database"); - // [START rtdb_social_write_fan_out] function writeNewPost(uid, username, picture, title, body) { const db = getDatabase(); diff --git a/database/emulator-suite.js b/database/emulator-suite.js index 8fe739e4..8da23e25 100644 --- a/database/emulator-suite.js +++ b/database/emulator-suite.js @@ -10,7 +10,7 @@ function onDocumentReady() { var db = firebase.database(); if (location.hostname === "localhost") { // Point to the RTDB emulator running on localhost. - db.useEmulator("localhost", 9000); + db.useEmulator("127.0.0.1", 9000); } // [END rtdb_emulator_connect] } diff --git a/database/package.json b/database/package.json index 356597c4..ea21b973 100644 --- a/database/package.json +++ b/database/package.json @@ -6,6 +6,6 @@ }, "license": "Apache 2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/firebaseapp-next/firebaseapp.js b/firebaseapp-next/firebaseapp.js index 8bd6838f..54aa3137 100644 --- a/firebaseapp-next/firebaseapp.js +++ b/firebaseapp-next/firebaseapp.js @@ -25,3 +25,61 @@ function multpleFirebaseApps() { // getDatabase(secondaryApp) // [END firebase_secondary] } + +function defaultInitOptions() { + const firebaseConfig = { + // ... + }; + + // [START app_default_init_options] + const { initializeApp } = require("firebase/app"); + const { getStorage } = require("firebase/storage"); + const { getFirestore } = require("firebase/firestore"); + + // Initialize Firebase with a "default" Firebase project + const defaultProject = initializeApp(firebaseConfig); + + console.log(defaultProject.name); // "[DEFAULT]" + + // Option 1: Access Firebase services via the defaultProject variable + let defaultStorage = getStorage(defaultProject); + let defaultFirestore = getFirestore(defaultProject); + + // Option 2: Access Firebase services using shorthand notation + defaultStorage = getStorage(); + defaultFirestore = getFirestore(); + // [END app_default_init_options] +} + +function multiProjectInitOptions() { + const firebaseConfig = { + // ... + }; + + const otherProjectFirebaseConfig = { + // ... + }; + + // [START app_multi_project_init_options] + const { initializeApp, getApp } = require("firebase/app"); + const { getStorage } = require("firebase/storage"); + const { getFirestore } = require("firebase/firestore"); + + // Initialize Firebase with a default Firebase project + initializeApp(firebaseConfig); + + // Initialize Firebase with a second Firebase project + const otherProject = initializeApp(otherProjectFirebaseConfig, "other"); + + console.log(getApp().name); // "[DEFAULT]" + console.log(otherProject.name); // "otherProject" + + // Use the shorthand notation to access the default project's Firebase services + const defaultStorage = getStorage(); + const defaultFirestore = getFirestore(); + + // Use the otherProject variable to access the second project's Firebase services + const otherStorage = getStorage(otherProject); + const otherFirestore = getFirestore(otherProject); + // [END app_multi_project_init_options] +} diff --git a/firebaseapp-next/package.json b/firebaseapp-next/package.json index 4eec0161..13cc74cd 100644 --- a/firebaseapp-next/package.json +++ b/firebaseapp-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/firebaseapp/firebaseapp.js b/firebaseapp/firebaseapp.js index 88eedd46..e030583f 100644 --- a/firebaseapp/firebaseapp.js +++ b/firebaseapp/firebaseapp.js @@ -6,7 +6,7 @@ function multpleFirebaseApps() { // - Project ID // - App ID // - API Key - var secondaryAppConfig = { + const secondaryAppConfig = { projectId: "", appId: "", apiKey: "", @@ -17,8 +17,58 @@ function multpleFirebaseApps() { // [START firebase_secondary] // Initialize another app with a different config - var secondaryApp = firebase.initializeApp(secondaryAppConfig, "secondary"); + const secondaryApp = firebase.initializeApp(secondaryAppConfig, "secondary"); // Access services, such as the Realtime Database // secondaryApp.database(); // [END firebase_secondary] } + +function defaultInitOptions() { + const firebaseConfig = { + // ... + }; + + // [START app_default_init_options] + // Initialize Firebase with a "default" Firebase project + const defaultProject = firebase.initializeApp(firebaseConfig); + + console.log(defaultProject.name); // "[DEFAULT]" + + // Option 1: Access Firebase services via the defaultProject variable + let defaultStorage = defaultProject.storage(); + let defaultFirestore = defaultProject.firestore(); + + // Option 2: Access Firebase services using shorthand notation + defaultStorage = firebase.storage(); + defaultFirestore = firebase.firestore(); + // [END app_default_init_options] +} + +function multiProjectInitOptions() { + const firebaseConfig = { + // ... + }; + + const otherProjectFirebaseConfig = { + // ... + }; + + // [START app_multi_project_init_options] + // Initialize Firebase with a default Firebase project + firebase.initializeApp(firebaseConfig); + + // Initialize Firebase with a second Firebase project + const otherProject = firebase.initializeApp(otherProjectFirebaseConfig, "other"); + + console.log(firebase.app().name); // "[DEFAULT]" + console.log(otherProject.name); // "otherProject" + + // Use the shorthand notation to access the default project's Firebase services + const defaultStorage = firebase.storage(); + const defaultFirestore = firebase.firestore(); + + // Use the otherProject variable to access the second project's Firebase services + const otherStorage = otherProject.storage(); + const otherFirestore = otherProject.firestore(); + // [END app_multi_project_init_options] +} diff --git a/firebaseapp/package.json b/firebaseapp/package.json index 65e8ce77..5226e2a0 100644 --- a/firebaseapp/package.json +++ b/firebaseapp/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/firebaseserverapp-next/firebaseserverapp.js b/firebaseserverapp-next/firebaseserverapp.js new file mode 100644 index 00000000..d0ab338c --- /dev/null +++ b/firebaseserverapp-next/firebaseserverapp.js @@ -0,0 +1,27 @@ +// @ts-nocheck +// [START serverapp_auth] +import { initializeServerApp } from 'firebase/app'; +import { getAuth } from 'firebase/auth'; +import { headers } from 'next/headers'; +import { redirect } from 'next/navigation'; + +export default function MyServerComponent() { + + // Get relevant request headers (in Next.JS) + const authIdToken = headers().get('Authorization')?.split('Bearer ')[1]; + + // Initialize the FirebaseServerApp instance. + const serverApp = initializeServerApp(firebaseConfig, { authIdToken }); + + // Initialize Firebase Authentication using the FirebaseServerApp instance. + const auth = getAuth(serverApp); + + if (auth.currentUser) { + redirect('/profile'); + } + + // ... +} +// [END serverapp_auth] + +const firebaseConfig = {}; diff --git a/firebaseserverapp-next/package.json b/firebaseserverapp-next/package.json new file mode 100644 index 00000000..0836b0b2 --- /dev/null +++ b/firebaseserverapp-next/package.json @@ -0,0 +1,12 @@ +{ + "name": "firebaseserverapp-next", + "version": "1.0.0", + "scripts": { + "compile": "cp ../tsconfig.json.template ./tsconfig.json && tsc" + }, + "license": "Apache-2.0", + "dependencies": { + "firebase": "^10.0.0", + "next": "^14.1.3" + } +} diff --git a/firestore-next/emulator-suite.js b/firestore-next/emulator-suite.js index 30ad24eb..edc900c1 100644 --- a/firestore-next/emulator-suite.js +++ b/firestore-next/emulator-suite.js @@ -7,6 +7,6 @@ function onDocumentReady() { // firebaseApps previously initialized using initializeApp() const db = getFirestore(); - connectFirestoreEmulator(db, 'localhost', 8080); + connectFirestoreEmulator(db, '127.0.0.1', 8080); // [END fs_emulator_connect] } diff --git a/firestore-next/package.json b/firestore-next/package.json index f15f2ed0..ef3b8708 100644 --- a/firestore-next/package.json +++ b/firestore-next/package.json @@ -6,7 +6,7 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8", + "firebase": "^10.0.0", "geofire-common": "^5.1.0" }, "devDependencies": { diff --git a/firestore-next/test.firestore.js b/firestore-next/test.firestore.js index 71c54b95..969c1654 100644 --- a/firestore-next/test.firestore.js +++ b/firestore-next/test.firestore.js @@ -583,7 +583,7 @@ describe("firestore", () => { if (docSnap.exists()) { console.log("Document data:", docSnap.data()); } else { - // doc.data() will be undefined in this case + // docSnap.data() will be undefined in this case console.log("No such document!"); } // [END get_document] @@ -683,6 +683,18 @@ describe("firestore", () => { // [END get_multiple_all] }); + it("should get all documents from a subcollection", async () => { + // [START firestore_query_subcollection] + const { collection, getDocs } = require("firebase/firestore"); + // Query a reference to a subcollection + const querySnapshot = await getDocs(collection(db, "cities", "SF", "landmarks")); + querySnapshot.forEach((doc) => { + // doc.data() is never undefined for query doc snapshots + console.log(doc.id, " => ", doc.data()); + }); + // [END firestore_query_subcollection] + }); + it("should listen on multiple documents #UNVERIFIED", (done) => { // [START listen_multiple] const { collection, query, where, onSnapshot } = require("firebase/firestore"); @@ -908,7 +920,7 @@ describe("firestore", () => { // [START in_filter_with_array] const { query, where } = require("firebase/firestore"); - const q = query(citiesRef, where('regions', 'in', [['west_coast', 'east_coast']])); + const q = query(citiesRef, where('regions', 'in', [['west_coast'], ['east_coast']])); // [END in_filter_with_array] } }); @@ -1048,7 +1060,7 @@ describe("firestore", () => { const docSnap = await getDoc(doc(citiesRef, "SF")); // Get all cities with a population bigger than San Francisco - const biggerThanSf = query(citiesRef, orderBy("popuation"), startAt(docSnap)); + const biggerThanSf = query(citiesRef, orderBy("population"), startAt(docSnap)); // ... // [END start_doc] }); @@ -1095,48 +1107,48 @@ describe("firestore", () => { describe('collectionGroup(landmarks)', () => { it("should setup example data", async () => { // [START fs_collection_group_query_data_setup] - const { collection, doc, setDoc } = require("firebase/firestore"); + const { collection, addDoc } = require("firebase/firestore"); const citiesRef = collection(db, 'cities'); await Promise.all([ - setDoc(doc(citiesRef, 'SF', 'landmarks'), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Golden Gate Bridge', type: 'bridge' }), - setDoc(doc(citiesRef, 'SF', 'landmarks'), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Legion of Honor', type: 'museum' }), - setDoc(doc(citiesRef, 'LA', 'landmarks'), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'Griffith Park', type: 'park' }), - setDoc(doc(citiesRef, 'LA', 'landmarks'), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'The Getty', type: 'museum' }), - setDoc(doc(citiesRef, 'DC', 'landmarks'), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'Lincoln Memorial', type: 'memorial' }), - setDoc(doc(citiesRef, 'DC', 'landmarks'), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'National Air and Space Museum', type: 'museum' }), - setDoc(doc(citiesRef, 'TOK', 'landmarks'), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'Ueno Park', type: 'park' }), - setDoc(doc(citiesRef, 'TOK', 'landmarks'), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'National Museum of Nature and Science', type: 'museum' }), - setDoc(doc(citiesRef, 'BJ', 'landmarks'), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Jingshan Park', type: 'park' }), - setDoc(doc(citiesRef, 'BJ', 'landmarks'), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Beijing Ancient Observatory', type: 'museum' }) @@ -1158,6 +1170,27 @@ describe("firestore", () => { }); }); + describe("aggregate queries", () => { + it("should fetch the count of documents in a collection", async () => { + const { collection, getCountFromServer } = require("firebase/firestore"); + // [START count_aggregate_collection] + const coll = collection(db, "cities"); + const snapshot = await getCountFromServer(coll); + console.log('count: ', snapshot.data().count); + // [END count_aggregate_collection] + }); + + it("should fetch the count of documents in a query", async () => { + const { collection, getCountFromServer, where, query } = require("firebase/firestore"); + // [START count_aggregate_query] + const coll = collection(db, "cities"); + const q = query(coll, where("state", "==", "CA")); + const snapshot = await getCountFromServer(q); + console.log('count: ', snapshot.data().count); + // [END count_aggregate_query] + }); + }); + // TODO: Break out into separate file describe("solution-aggregation", () => { it("should update a restaurant in a transaction #UNVERIFIED", async () => { diff --git a/firestore/emulator-suite.js b/firestore/emulator-suite.js index 714d38e7..03aef1e9 100644 --- a/firestore/emulator-suite.js +++ b/firestore/emulator-suite.js @@ -6,7 +6,7 @@ function onDocumentReady() { // Firebase previously initialized using firebase.initializeApp(). var db = firebase.firestore(); if (location.hostname === "localhost") { - db.useEmulator("localhost", 8080); + db.useEmulator("127.0.0.1", 8080); } // [END fs_emulator_connect] } diff --git a/firestore/index.html b/firestore/index.html index 107339fc..3599ca13 100644 --- a/firestore/index.html +++ b/firestore/index.html @@ -12,8 +12,8 @@ - - + + diff --git a/firestore/package.json b/firestore/package.json index b831157a..73bbb88c 100644 --- a/firestore/package.json +++ b/firestore/package.json @@ -6,7 +6,7 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1", + "firebase": "^8.10.0", "geofire-common": "^5.1.0" }, "devDependencies": { diff --git a/firestore/test.firestore.js b/firestore/test.firestore.js index 2aadf8d5..20032d36 100644 --- a/firestore/test.firestore.js +++ b/firestore/test.firestore.js @@ -600,7 +600,7 @@ describe("firestore", () => { var docRef = db.collection("cities").doc("SF"); // Valid options for source are 'server', 'cache', or - // 'default'. See https://firebase.google.com/docs/reference/js/firebase.firestore.GetOptions + // 'default'. See https://firebase.google.com/docs/reference/js/v8/firebase.firestore.GetOptions // for more information. var getOptions = { source: 'cache' @@ -893,7 +893,7 @@ describe("firestore", () => { // [START in_filter_with_array] citiesRef.where('regions', 'in', - [['west_coast', 'east_coast']]); + [['west_coast'], ['east_coast']]); // [END in_filter_with_array] }); @@ -1011,7 +1011,7 @@ describe("firestore", () => { // [END start_multiple_orderby] }); - it("shoud paginate", () => { + it("should paginate", () => { // [START paginate] var first = db.collection("cities") .orderBy("population") diff --git a/firestore/test.solution-counters.js b/firestore/test.solution-counters.js index c8c62fe6..c7c51cff 100644 --- a/firestore/test.solution-counters.js +++ b/firestore/test.solution-counters.js @@ -22,7 +22,7 @@ function createCounter(ref, num_shards) { // [END create_counter] // [START increment_counter] -function incrementCounter(db, ref, num_shards) { +function incrementCounter(ref, num_shards) { // Select a shard of the counter at random const shard_id = Math.floor(Math.random() * num_shards).toString(); const shard_ref = ref.collection('shards').doc(shard_id); @@ -67,7 +67,7 @@ describe("firestore-solution-counters", () => { // Create a counter, then increment it const ref = db.collection('counters').doc(); return createCounter(ref, 10).then(() => { - return incrementCounter(db, ref, 10); + return incrementCounter(ref, 10); }); }); @@ -75,7 +75,7 @@ describe("firestore-solution-counters", () => { // Create a counter, increment it, then get the count const ref = db.collection('counters').doc(); return createCounter(ref, 10).then(() => { - return incrementCounter(db, ref, 10); + return incrementCounter(ref, 10); }).then(() => { return getCount(ref); }); diff --git a/functions-next/emulator-suite.js b/functions-next/emulator-suite.js index 7a750fc4..db7fd49d 100644 --- a/functions-next/emulator-suite.js +++ b/functions-next/emulator-suite.js @@ -15,7 +15,7 @@ export function emulatorSettings() { const { getFunctions, connectFunctionsEmulator } = require("firebase/functions"); const functions = getFunctions(getApp()); - connectFunctionsEmulator(functions, "localhost", 5001); + connectFunctionsEmulator(functions, "127.0.0.1", 5001); // [END fb_functions_emulator_connect] } diff --git a/functions-next/package.json b/functions-next/package.json index 8e0e6422..14f097ee 100644 --- a/functions-next/package.json +++ b/functions-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/functions/emulator-suite.js b/functions/emulator-suite.js index a9cdc7d7..e0413370 100644 --- a/functions/emulator-suite.js +++ b/functions/emulator-suite.js @@ -3,6 +3,6 @@ import "firebase/functions"; function emulatorSettings() { // [START fb_functions_emulator_connect] - firebase.functions().useEmulator("localhost", 5001); + firebase.functions().useEmulator("127.0.0.1", 5001); // [END fb_functions_emulator_connect] } diff --git a/functions/package.json b/functions/package.json index c2ad0aa1..653086c9 100644 --- a/functions/package.json +++ b/functions/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/installations/package.json b/installations/package.json index 412aade6..1395fca3 100644 --- a/installations/package.json +++ b/installations/package.json @@ -4,6 +4,6 @@ "scripts": {}, "license": "Apache 2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/messaging-next/package.json b/messaging-next/package.json index 2137e3e2..e4887a2a 100644 --- a/messaging-next/package.json +++ b/messaging-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/messaging-next/service-worker.js b/messaging-next/service-worker.js index ce0ac6b8..55f07524 100644 --- a/messaging-next/service-worker.js +++ b/messaging-next/service-worker.js @@ -16,7 +16,7 @@ let self; function initInSw() { // [START messaging_init_in_sw] const { initializeApp } = require("firebase/app"); - const { getMessaging } = require("firebase/messaging"); + const { getMessaging } = require("firebase/messaging/sw"); // Initialize the Firebase app in the service worker by passing in // your app's Firebase config object. @@ -40,7 +40,7 @@ function initInSw() { function onBackgroundMessage() { // [START messaging_on_background_message] - const { getMessaging } = require("firebase/messaging"); + const { getMessaging } = require("firebase/messaging/sw"); const { onBackgroundMessage } = require("firebase/messaging/sw"); const messaging = getMessaging(); diff --git a/messaging/package.json b/messaging/package.json index 35a95be2..96a5720d 100644 --- a/messaging/package.json +++ b/messaging/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/messaging/service-worker.js b/messaging/service-worker.js index 65f0aa01..1a202159 100644 --- a/messaging/service-worker.js +++ b/messaging/service-worker.js @@ -1,5 +1,5 @@ -import firebase from "firebase/app"; -import "firebase/messaging"; +import firebase from 'firebase/app'; +import 'firebase/messaging'; // See: https://github.com/microsoft/TypeScript/issues/14877 /** @type {ServiceWorkerGlobalScope} */ @@ -10,8 +10,9 @@ function initInSw() { // Give the service worker access to Firebase Messaging. // Note that you can only use Firebase Messaging here. Other Firebase libraries // are not available in the service worker. - importScripts('https://www.gstatic.com/firebasejs/8.8.1/firebase-app.js'); - importScripts('https://www.gstatic.com/firebasejs/8.8.1/firebase-messaging.js'); + // Replace 10.13.2 with latest version of the Firebase JS SDK. + importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-app-compat.js'); + importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-compat.js'); // Initialize the Firebase app in the service worker by passing in // your app's Firebase config object. @@ -38,16 +39,18 @@ function onBackgroundMessage() { // [START messaging_on_background_message] messaging.onBackgroundMessage((payload) => { - console.log('[firebase-messaging-sw.js] Received background message ', payload); + console.log( + '[firebase-messaging-sw.js] Received background message ', + payload + ); // Customize notification here const notificationTitle = 'Background Message Title'; const notificationOptions = { body: 'Background Message body.', icon: '/firebase-logo.png' }; - - self.registration.showNotification(notificationTitle, - notificationOptions); + + self.registration.showNotification(notificationTitle, notificationOptions); }); // [END messaging_on_background_message] } diff --git a/package.json b/package.json index e7621ce2..cb7d9157 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/node": "^15.12.2", - "eslint": "^7.16.0", - "pnpm": "^6.7.4", + "@types/node": "^16.7.10", + "eslint": "^7.32.0", + "pnpm": "^6.14.6", "rimraf": "^3.0.2", - "ts-node": "^9.0.0", - "typescript": "^3.8.3" + "ts-node": "^10.2.1", + "typescript": "^4.4.2" } } diff --git a/perf-next/index.js b/perf-next/index.js index 20f9b4f4..e41aa1b0 100644 --- a/perf-next/index.js +++ b/perf-next/index.js @@ -4,22 +4,28 @@ const perf = getInstance(); function intialize() { - // [START perf_initialize] + // [START perf_import_app] const { initializeApp } = require("firebase/app"); + // [END perf_import_app] + // [START perf_import] const { getPerformance } = require("firebase/performance"); + // [END perf_import] + // [START perf_initialize_app] // TODO: Replace the following with your app's Firebase project configuration - // See: https://firebase.google.com/docs/web/setup#config-object + // See: https://firebase.google.com/docs/web/learn-more#config-object const firebaseConfig = { // ... }; // Initialize Firebase const app = initializeApp(firebaseConfig); + // [END perf_initialize_app] + // [START perf_singleton] // Initialize Performance Monitoring and get a reference to the service const perf = getPerformance(app); - // [END perf_initialize] + // [END perf_singleton] } export function getInstance() { diff --git a/perf-next/package.json b/perf-next/package.json index 9321e3c8..688f6db0 100644 --- a/perf-next/package.json +++ b/perf-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/perf/index.js b/perf/index.js index 6d512e32..c5ae8b22 100644 --- a/perf/index.js +++ b/perf/index.js @@ -1,22 +1,28 @@ +// [START perf_import_app] import firebase from "firebase/app"; +// [END perf_import_app] +// [START perf_import] import "firebase/performance"; +// [END perf_import] const perf = firebase.performance(); function intialize() { - // [START perf_initialize] + // [START perf_initialize_app] // TODO: Replace the following with your app's Firebase project configuration - // See: https://firebase.google.com/docs/web/setup#config-object - var firebaseConfig = { + // See: https://firebase.google.com/docs/web/learn-more#config-object + const firebaseConfig = { // ... }; // Initialize Firebase firebase.initializeApp(firebaseConfig); + // [END perf_initialize_app] + // [START perf_singleton] // Initialize Performance Monitoring and get a reference to the service - var perf = firebase.performance(); - // [END perf_initialize] + const perf = firebase.performance(); + // [END perf_singleton] } function addCustomTrace() { diff --git a/perf/package.json b/perf/package.json index d6f57401..61906b8e 100644 --- a/perf/package.json +++ b/perf/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/remoteconfig-next/index.js b/remoteconfig-next/index.js index aeeb263a..287f3c99 100644 --- a/remoteconfig-next/index.js +++ b/remoteconfig-next/index.js @@ -14,6 +14,7 @@ function getInstance() { function setMinimumFetchTime() { const remoteConfig = getInstance(); // [START rc_set_minimum_fetch_time] + // The default and recommended production fetch interval for Remote Config is 12 hours remoteConfig.settings.minimumFetchIntervalMillis = 3600000; // [END rc_set_minimum_fetch_time] } diff --git a/remoteconfig-next/package.json b/remoteconfig-next/package.json index 6f8e1636..952b1540 100644 --- a/remoteconfig-next/package.json +++ b/remoteconfig-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/remoteconfig/package.json b/remoteconfig/package.json index 8d5f02f8..8437cbd2 100644 --- a/remoteconfig/package.json +++ b/remoteconfig/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } } diff --git a/scripts/separate-snippets.ts b/scripts/separate-snippets.ts index 86821383..b2f41de3 100644 --- a/scripts/separate-snippets.ts +++ b/scripts/separate-snippets.ts @@ -18,6 +18,15 @@ const RE_END_SNIPPET = /\[END\s+([A-Za-z_]+)\s*\]/; // TODO: Handle multiline imports? const RE_REQUIRE = /const {(.+?)} = require\((.+?)\)/; +// Regex for ref docs URLs +// eg. "https://firebase.google.com/docs/reference/js/v8/firebase.User" +const RE_REF_DOCS = /https:\/\/firebase\.google\.com\/docs\/reference\/js\/(.*)/; + +// Maps v8 ref docs URLs to their v9 counterpart +const REF_DOCS_MAPPINGS: { [key: string]: string } = { + "v8/firebase.User" : "auth.user" +}; + type SnippetsConfig = { enabled: boolean; suffix: string; @@ -30,6 +39,23 @@ function isBlank(line: string) { return line.trim().length === 0; } +/** + * Replace all v8 ref doc urls with their v9 counterpart. + */ +function replaceRefDocsUrls(lines: string[]) { + const outputLines = []; + for (const line of lines) { + if (line.match(RE_REF_DOCS)) { + outputLines.push(line.replace(RE_REF_DOCS, (match: string, p1?: string) => { + return p1 ? `https://firebase.google.com/docs/reference/js/${REF_DOCS_MAPPINGS[p1]}` : match; + })); + } else { + outputLines.push(line); + } + } + return outputLines; +} + /** * Replace all const { foo } = require('bar') with import { foo } from 'bar'; */ @@ -77,7 +103,7 @@ function adjustIndentation(lines: string[]) { if (isBlank(line)) { outputLines.push(""); } else { - outputLines.push(line.substr(minIndent)); + outputLines.push(line.slice(minIndent)); } } return outputLines; @@ -119,6 +145,7 @@ function processSnippet( outputLines = addSuffixToSnippetNames(outputLines, snippetSuffix); outputLines = adjustIndentation(outputLines); outputLines = removeFirstLineAfterComments(outputLines); + outputLines = replaceRefDocsUrls(outputLines); // Add a preamble to every snippet const preambleLines = [ @@ -171,12 +198,15 @@ function collectSnippets(filePath: string): SnippetsConfig { const suffixLine = lines.find((l) => !!l.match(RE_SNIPPETS_SUFFIX)); if (suffixLine) { const m = suffixLine.match(RE_SNIPPETS_SUFFIX); - config.suffix = m[1]; + + if (m && m[1]) { + config.suffix = m[1]; + } } // A temporary array holding the names of snippets we're currently within. // This allows for handling nested snippets. - let inSnippetNames = []; + let inSnippetNames: string[] = []; for (const line of lines) { const startMatch = line.match(RE_START_SNIPPET); diff --git a/snippets/analytics-next/index/analytics_log_event_params.js b/snippets/analytics-next/index/analytics_log_event_params.js index 27e6528d..e79d7ec0 100644 --- a/snippets/analytics-next/index/analytics_log_event_params.js +++ b/snippets/analytics-next/index/analytics_log_event_params.js @@ -10,7 +10,6 @@ import { getAnalytics, logEvent } from "firebase/analytics"; const analytics = getAnalytics(); logEvent(analytics, 'select_content', { content_type: 'image', - content_id: 'P12453', - items: [{ name: 'Kittens' }] + content_id: 'P12453' }); // [END analytics_log_event_params_modular] \ No newline at end of file diff --git a/snippets/analytics-next/index/analytics_record_screen_view.js b/snippets/analytics-next/index/analytics_record_screen_view.js new file mode 100644 index 00000000..2eef20b3 --- /dev/null +++ b/snippets/analytics-next/index/analytics_record_screen_view.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./analytics-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START analytics_record_screen_view_modular] +import { getAnalytics, logEvent } from "firebase/analytics"; + +const analytics = getAnalytics(); +logEvent(analytics, 'screen_view', { + firebase_screen: screenName, + firebase_screen_class: screenClass +}); +// [END analytics_record_screen_view_modular] \ No newline at end of file diff --git a/snippets/auth-next/apple/auth_apple_nonce_node.js b/snippets/auth-next/apple/auth_apple_nonce_node.js index 26bb2ef0..9dd417a5 100644 --- a/snippets/auth-next/apple/auth_apple_nonce_node.js +++ b/snippets/auth-next/apple/auth_apple_nonce_node.js @@ -17,7 +17,7 @@ const generateNonce = (length) => { crypto.randomFillSync(buf); nonce = decoder.write(buf); } - return nonce.substr(0, length); + return nonce.slice(0, length); }; const unhashedNonce = generateNonce(10); diff --git a/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js b/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js index 129fe920..cd40151d 100644 --- a/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js +++ b/snippets/auth-next/apple/auth_apple_reauthenticate_popup.js @@ -32,7 +32,7 @@ reauthenticateWithPopup(auth.currentUser, provider) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/apple/auth_apple_signin_popup.js b/snippets/auth-next/apple/auth_apple_signin_popup.js index 2db09607..e3a0f11b 100644 --- a/snippets/auth-next/apple/auth_apple_signin_popup.js +++ b/snippets/auth-next/apple/auth_apple_signin_popup.js @@ -18,6 +18,7 @@ signInWithPopup(auth, provider) const accessToken = credential.accessToken; const idToken = credential.idToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -25,7 +26,7 @@ signInWithPopup(auth, provider) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/apple/auth_apple_signin_redirect_result.js b/snippets/auth-next/apple/auth_apple_signin_redirect_result.js index 68dba4ab..654f95e5 100644 --- a/snippets/auth-next/apple/auth_apple_signin_redirect_result.js +++ b/snippets/auth-next/apple/auth_apple_signin_redirect_result.js @@ -25,7 +25,7 @@ getRedirectResult(auth) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = OAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/cordova/auth_cordova_redirect_result.js b/snippets/auth-next/cordova/auth_cordova_redirect_result.js index 7bcc69a3..f1c87596 100644 --- a/snippets/auth-next/cordova/auth_cordova_redirect_result.js +++ b/snippets/auth-next/cordova/auth_cordova_redirect_result.js @@ -5,7 +5,7 @@ // 'npm run snippets'. // [START auth_cordova_redirect_result_modular] -import { getAuth, getRedirectResult, GoogleAuthProvider } from "firebase/auth"; +import { getAuth, getRedirectResult, GoogleAuthProvider } from "firebase/auth/cordova"; const auth = getAuth(); getRedirectResult(auth) diff --git a/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js b/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js index 5aaee22d..ed3cc8d1 100644 --- a/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js +++ b/snippets/auth-next/cordova/auth_cordova_sign_in_redirect.js @@ -5,7 +5,7 @@ // 'npm run snippets'. // [START auth_cordova_sign_in_redirect_modular] -import { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } from "firebase/auth"; +import { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } from "firebase/auth/cordova"; const auth = getAuth(); signInWithRedirect(auth, new GoogleAuthProvider()) diff --git a/snippets/auth-next/cordova/auth_create_google_provider.js b/snippets/auth-next/cordova/auth_create_google_provider.js index aab60312..fcf96401 100644 --- a/snippets/auth-next/cordova/auth_create_google_provider.js +++ b/snippets/auth-next/cordova/auth_create_google_provider.js @@ -5,7 +5,7 @@ // 'npm run snippets'. // [START auth_create_google_provider_modular] -import { GoogleAuthProvider } from "firebase/auth"; +import { GoogleAuthProvider } from "firebase/auth/cordova"; const provider = new GoogleAuthProvider(); // [END auth_create_google_provider_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_get_auth_equivalent.js b/snippets/auth-next/custom-dependencies/auth_get_auth_equivalent.js new file mode 100644 index 00000000..37292487 --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_get_auth_equivalent.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_get_auth_equivalent_modular] +import {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, browserSessionPersistence, indexedDBLocalPersistence} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence], + popupRedirectResolver: browserPopupRedirectResolver, +}); +// [END auth_get_auth_equivalent_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_only_browser_local.js b/snippets/auth-next/custom-dependencies/auth_only_browser_local.js new file mode 100644 index 00000000..549307ac --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_only_browser_local.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_only_browser_local_modular] +import {initializeAuth, browserLocalPersistence} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: browserLocalPersistence, + // No popupRedirectResolver defined +}); +// [END auth_only_browser_local_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_only_indexed_db.js b/snippets/auth-next/custom-dependencies/auth_only_indexed_db.js new file mode 100644 index 00000000..1427ae6b --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_only_indexed_db.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_only_indexed_db_modular] +import {initializeAuth, indexedDBLocalPersistence} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: indexedDBLocalPersistence, + // No popupRedirectResolver defined +}); +// [END auth_only_indexed_db_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-dependencies/auth_sign_in_redirect_manual_deps.js b/snippets/auth-next/custom-dependencies/auth_sign_in_redirect_manual_deps.js new file mode 100644 index 00000000..75fd0d5d --- /dev/null +++ b/snippets/auth-next/custom-dependencies/auth_sign_in_redirect_manual_deps.js @@ -0,0 +1,18 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/custom-dependencies.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_sign_in_redirect_manual_deps_modular] +import {initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, indexedDBLocalPersistence, signInWithRedirect, GoogleAuthProvider} from "firebase/auth"; +import {initializeApp} from "firebase/app"; + +const app = initializeApp({/** Your app config */}); +const auth = initializeAuth(app, { + persistence: [indexedDBLocalPersistence, browserLocalPersistence], +}); + +// Later +signInWithRedirect(auth, new GoogleAuthProvider(), browserPopupRedirectResolver); +// [END auth_sign_in_redirect_manual_deps_modular] \ No newline at end of file diff --git a/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js b/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js index 6dec3399..d0a22696 100644 --- a/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js +++ b/snippets/auth-next/custom-email-handler/auth_handle_mgmt_query_params.js @@ -23,8 +23,8 @@ document.addEventListener('DOMContentLoaded', () => { // Configure the Firebase SDK. // This is the minimum configuration required for the API to be used. const config = { - 'apiKey': "YOU_API_KEY" // Copy this key from the web initialization - // snippet found in the Firebase console. + 'apiKey': "YOUR_API_KEY" // Copy this key from the web initialization + // snippet found in the Firebase console. }; const app = initializeApp(config); const auth = getAuth(app); diff --git a/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js b/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js index a1480a11..010b5c09 100644 --- a/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js +++ b/snippets/auth-next/email-link-auth/auth_email_link_actioncode_settings.js @@ -19,6 +19,7 @@ const actionCodeSettings = { installApp: true, minimumVersion: '12' }, - dynamicLinkDomain: 'example.page.link' + // The domain must be configured in Firebase Hosting and owned by the project. + linkDomain: 'custom-domain.com' }; // [END auth_email_link_actioncode_settings_modular] \ No newline at end of file diff --git a/snippets/auth-next/email-link-auth/email_link_complete.js b/snippets/auth-next/email-link-auth/email_link_complete.js index b42b9af9..dbe1143d 100644 --- a/snippets/auth-next/email-link-auth/email_link_complete.js +++ b/snippets/auth-next/email-link-auth/email_link_complete.js @@ -26,11 +26,13 @@ if (isSignInWithEmailLink(auth, window.location.href)) { .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); - // You can access the new user via result.user - // Additional user info profile not available via: - // result.additionalUserInfo.profile == null + // You can access the new user by importing getAdditionalUserInfo + // and calling it with result: + // getAdditionalUserInfo(result) + // You can access the user's profile via: + // getAdditionalUserInfo(result)?.profile // You can check if the user is new or existing: - // result.additionalUserInfo.isNewUser + // getAdditionalUserInfo(result)?.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code diff --git a/snippets/auth-next/email/auth_signup_password.js b/snippets/auth-next/email/auth_signup_password.js index 00aa9bd5..936b64ce 100644 --- a/snippets/auth-next/email/auth_signup_password.js +++ b/snippets/auth-next/email/auth_signup_password.js @@ -10,7 +10,7 @@ import { getAuth, createUserWithEmailAndPassword } from "firebase/auth"; const auth = getAuth(); createUserWithEmailAndPassword(auth, email, password) .then((userCredential) => { - // Signed in + // Signed up const user = userCredential.user; // ... }) diff --git a/snippets/auth-next/emulator-suite/auth_emulator_connect.js b/snippets/auth-next/emulator-suite/auth_emulator_connect.js index dd0b2e37..525a92b8 100644 --- a/snippets/auth-next/emulator-suite/auth_emulator_connect.js +++ b/snippets/auth-next/emulator-suite/auth_emulator_connect.js @@ -8,5 +8,5 @@ import { getAuth, connectAuthEmulator } from "firebase/auth"; const auth = getAuth(); -connectAuthEmulator(auth, "http://localhost:9099"); +connectAuthEmulator(auth, "http://127.0.0.1:9099"); // [END auth_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/auth-next/facebook/auth_facebook_callback.js b/snippets/auth-next/facebook/auth_facebook_callback.js index 8596bb68..63106871 100644 --- a/snippets/auth-next/facebook/auth_facebook_callback.js +++ b/snippets/auth-next/facebook/auth_facebook_callback.js @@ -26,7 +26,7 @@ function checkLoginState(response) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/facebook/auth_facebook_provider_credential.js b/snippets/auth-next/facebook/auth_facebook_provider_credential.js new file mode 100644 index 00000000..b7bbca25 --- /dev/null +++ b/snippets/auth-next/facebook/auth_facebook_provider_credential.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/facebook.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_facebook_provider_credential_modular] +import { FacebookAuthProvider } from "firebase/auth"; + +const credential = FacebookAuthProvider.credential(accessToken); +// [END auth_facebook_provider_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/facebook/auth_facebook_signin_credential.js b/snippets/auth-next/facebook/auth_facebook_signin_credential.js index dcd42c7e..3b784f24 100644 --- a/snippets/auth-next/facebook/auth_facebook_signin_credential.js +++ b/snippets/auth-next/facebook/auth_facebook_signin_credential.js @@ -19,7 +19,7 @@ signInWithCredential(auth, credential) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/facebook/auth_facebook_signin_popup.js b/snippets/auth-next/facebook/auth_facebook_signin_popup.js index 2bc014ed..524a11ac 100644 --- a/snippets/auth-next/facebook/auth_facebook_signin_popup.js +++ b/snippets/auth-next/facebook/auth_facebook_signin_popup.js @@ -17,6 +17,7 @@ signInWithPopup(auth, provider) const credential = FacebookAuthProvider.credentialFromResult(result); const accessToken = credential.accessToken; + // IdP data available using getAdditionalUserInfo(result) // ... }) .catch((error) => { @@ -24,7 +25,7 @@ signInWithPopup(auth, provider) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); diff --git a/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js b/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js index 49f3a494..c65c47d7 100644 --- a/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js +++ b/snippets/auth-next/facebook/auth_facebook_signin_redirect_result.js @@ -15,12 +15,14 @@ getRedirectResult(auth) const token = credential.accessToken; const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // AuthCredential type that was used. const credential = FacebookAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/github/auth_github_signin_popup.js b/snippets/auth-next/github/auth_github_signin_popup.js index 74e76cc9..3839a70f 100644 --- a/snippets/auth-next/github/auth_github_signin_popup.js +++ b/snippets/auth-next/github/auth_github_signin_popup.js @@ -16,13 +16,14 @@ signInWithPopup(auth, provider) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/github/auth_github_signin_redirect_result.js b/snippets/auth-next/github/auth_github_signin_redirect_result.js index 6147d9de..fb5f7ca2 100644 --- a/snippets/auth-next/github/auth_github_signin_redirect_result.js +++ b/snippets/auth-next/github/auth_github_signin_redirect_result.js @@ -19,12 +19,14 @@ getRedirectResult(auth) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GithubAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_build_signin.js b/snippets/auth-next/google-signin/auth_google_build_signin.js index 6df84e3e..98f35eb2 100644 --- a/snippets/auth-next/google-signin/auth_google_build_signin.js +++ b/snippets/auth-next/google-signin/auth_google_build_signin.js @@ -17,7 +17,7 @@ signInWithCredential(auth, credential).catch((error) => { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_callback.js b/snippets/auth-next/google-signin/auth_google_callback.js index 27aa8dc6..873778dd 100644 --- a/snippets/auth-next/google-signin/auth_google_callback.js +++ b/snippets/auth-next/google-signin/auth_google_callback.js @@ -25,7 +25,7 @@ function onSignIn(googleUser) { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_provider_credential.js b/snippets/auth-next/google-signin/auth_google_provider_credential.js new file mode 100644 index 00000000..924aa167 --- /dev/null +++ b/snippets/auth-next/google-signin/auth_google_provider_credential.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/google-signin.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_google_provider_credential_modular] +import { GoogleAuthProvider } from "firebase/auth"; + +const credential = GoogleAuthProvider.credential(idToken); +// [END auth_google_provider_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/google-signin/auth_google_signin_credential.js b/snippets/auth-next/google-signin/auth_google_signin_credential.js index a3a8808e..25c6f3ba 100644 --- a/snippets/auth-next/google-signin/auth_google_signin_credential.js +++ b/snippets/auth-next/google-signin/auth_google_signin_credential.js @@ -10,7 +10,7 @@ signInWithCredential(auth, credential).catch((error) => { const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The credential that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_signin_popup.js b/snippets/auth-next/google-signin/auth_google_signin_popup.js index 55c46488..433bb88e 100644 --- a/snippets/auth-next/google-signin/auth_google_signin_popup.js +++ b/snippets/auth-next/google-signin/auth_google_signin_popup.js @@ -15,13 +15,14 @@ signInWithPopup(auth, provider) const token = credential.accessToken; // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js b/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js index a64977bb..2953ab5f 100644 --- a/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js +++ b/snippets/auth-next/google-signin/auth_google_signin_redirect_result.js @@ -16,12 +16,14 @@ getRedirectResult(auth) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = GoogleAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/index/auth_current_user.js b/snippets/auth-next/index/auth_current_user.js index c094a464..6925b021 100644 --- a/snippets/auth-next/index/auth_current_user.js +++ b/snippets/auth-next/index/auth_current_user.js @@ -12,7 +12,7 @@ const user = auth.currentUser; if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/auth.user // ... } else { // No user is signed in. diff --git a/snippets/auth-next/index/auth_init_custom_domain.js b/snippets/auth-next/index/auth_init_custom_domain.js new file mode 100644 index 00000000..971e5c56 --- /dev/null +++ b/snippets/auth-next/index/auth_init_custom_domain.js @@ -0,0 +1,17 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_init_custom_domain_modular] +import { initializeApp } from "firebase/app"; + +const firebaseConfig = { + apiKey: "...", + // By default, authDomain is '[YOUR_APP].firebaseapp.com'. + // You may replace it with a custom domain. + authDomain: '[YOUR_CUSTOM_DOMAIN]' +}; +const firebaseApp = initializeApp(firebaseConfig); +// [END auth_init_custom_domain_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_set_language_code.js b/snippets/auth-next/index/auth_set_language_code.js index 47e78295..fe9a2025 100644 --- a/snippets/auth-next/index/auth_set_language_code.js +++ b/snippets/auth-next/index/auth_set_language_code.js @@ -10,5 +10,5 @@ import { getAuth } from "firebase/auth"; const auth = getAuth(); auth.languageCode = 'it'; // To apply the default browser preference instead of explicitly setting it. -// firebase.auth().useDeviceLanguage(); +// auth.useDeviceLanguage(); // [END auth_set_language_code_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_signin_credential.js b/snippets/auth-next/index/auth_signin_credential.js index ba2db6b8..c2b027a3 100644 --- a/snippets/auth-next/index/auth_signin_credential.js +++ b/snippets/auth-next/index/auth_signin_credential.js @@ -19,7 +19,7 @@ signInWithCredential(auth, credential) const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // ... }); // [END auth_signin_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/index/auth_state_listener.js b/snippets/auth-next/index/auth_state_listener.js index aebe6818..0f3e4e88 100644 --- a/snippets/auth-next/index/auth_state_listener.js +++ b/snippets/auth-next/index/auth_state_listener.js @@ -11,7 +11,7 @@ const auth = getAuth(); onAuthStateChanged(auth, (user) => { if (user) { // User is signed in, see docs for a list of available properties - // https://firebase.google.com/docs/reference/js/firebase.User + // https://firebase.google.com/docs/reference/js/auth.user const uid = user.uid; // ... } else { diff --git a/snippets/auth-next/link-multiple-accounts/account_exists_popup.js b/snippets/auth-next/link-multiple-accounts/account_exists_popup.js new file mode 100644 index 00000000..2c667882 --- /dev/null +++ b/snippets/auth-next/link-multiple-accounts/account_exists_popup.js @@ -0,0 +1,61 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/link-multiple-accounts.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + + // [START account_exists_popup_modular] + import { signInWithPopup, signInWithEmailAndPassword, linkWithCredential } from "firebase/auth"; + + // User tries to sign in with Facebook. + signInWithPopup(auth, facebookProvider).catch((error) => { + // User's email already exists. + if (error.code === 'auth/account-exists-with-different-credential') { + // The pending Facebook credential. + const pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + + // Present the user with a list of providers they might have + // used to create the original account. + // Then, ask the user to sign in with the existing provider. + const method = promptUserForSignInMethod(); + + if (method === 'password') { + // TODO: Ask the user for their password. + // In real scenario, you should handle this asynchronously. + const password = promptUserForPassword(); + signInWithEmailAndPassword(auth, email, password).then((result) => { + return linkWithCredential(result.user, pendingCred); + }).then(() => { + // Facebook account successfully linked to the existing user. + goToApp(); + }); + return; + } + + // All other cases are external providers. + // Construct provider object for that provider. + // TODO: Implement getProviderForProviderId. + const provider = getProviderForProviderId(method); + // At this point, you should let the user know that they already have an + // account with a different provider, and validate they want to sign in + // with the new provider. + // Note: Browsers usually block popups triggered asynchronously, so in + // real app, you should ask the user to click on a "Continue" button + // that will trigger signInWithPopup(). + signInWithPopup(auth, provider).then((result) => { + // Note: Identity Platform doesn't control the provider's sign-in + // flow, so it's possible for the user to sign in with an account + // with a different email from the first one. + + // Link the Facebook credential. We have access to the pending + // credential, so we can directly call the link method. + linkWithCredential(result.user, pendingCred).then((userCred) => { + // Success. + goToApp(); + }); + }); + } +}); +// [END account_exists_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_account_exists_popup.js b/snippets/auth-next/multi-tenancy/multitenant_account_exists_popup.js new file mode 100644 index 00000000..7bf33262 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_account_exists_popup.js @@ -0,0 +1,44 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_account_exists_popup_modular] +import { signInWithPopup, fetchSignInMethodsForEmail, linkWithCredential } from "firebase/auth"; +// Step 1. +// User tries to sign in to the SAML provider in that tenant. +auth.tenantId = 'TENANT_ID'; +signInWithPopup(auth, samlProvider) + .catch((error) => { + // An error happened. + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + // The pending SAML credential. + const pendingCred = error.credential; + // The credential's tenantId if needed: error.tenantId + // The provider account's email address. + const email = error.customData.email; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(email, auth) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithPopup(auth, googleProvider) + .then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); + }); + } + }); + } + }); +// [END multitenant_account_exists_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_account_exists_redirect.js b/snippets/auth-next/multi-tenancy/multitenant_account_exists_redirect.js new file mode 100644 index 00000000..a81617dd --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_account_exists_redirect.js @@ -0,0 +1,51 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_account_exists_redirect_modular] +import { signInWithRedirect, getRedirectResult, fetchSignInMethodsForEmail, linkWithCredential } from "firebase/auth"; +// Step 1. +// User tries to sign in to SAML provider. +auth.tenantId = 'TENANT_ID'; +signInWithRedirect(auth, samlProvider); +var pendingCred; +// Redirect back from SAML IDP. auth.tenantId is null after redirecting. +getRedirectResult(auth).catch((error) => { + if (error.code === 'auth/account-exists-with-different-credential') { + // Step 2. + // User's email already exists. + const tenantId = error.tenantId; + // The pending SAML credential. + pendingCred = error.credential; + // The provider account's email address. + const email = error.customData.email; + // Need to set the tenant ID again as the page was reloaded and the + // previous setting was reset. + auth.tenantId = tenantId; + // Get sign-in methods for this email. + fetchSignInMethodsForEmail(auth, email) + .then((methods) => { + // Step 3. + // Ask the user to sign in with existing Google account. + if (methods[0] == 'google.com') { + signInWithRedirect(auth, googleProvider); + } + }); + } +}); + +// Redirect back from Google. auth.tenantId is null after redirecting. +getRedirectResult(auth).then((result) => { + // Step 4 + // Link the SAML AuthCredential to the existing user. + // result.user.tenantId is 'TENANT_ID'. + linkWithCredential(result.user, pendingCred) + .then((linkResult) => { + // SAML account successfully linked to the existing + // user. + goToApp(); + }); +}); +// [END multitenant_account_exists_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_account_linking.js b/snippets/auth-next/multi-tenancy/multitenant_account_linking.js new file mode 100644 index 00000000..c43ff90d --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_account_linking.js @@ -0,0 +1,34 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_account_linking_modular] +import { signInWithPopup, EmailAuthProvider, linkWithCredential, SAMLAuthProvider, signInWithCredential } from "firebase/auth"; +// Switch to TENANT_ID1 +auth.tenantId = 'TENANT_ID1'; + +// Sign-in with popup +signInWithPopup(auth, provider) + .then((userCredential) => { + // Existing user with e.g. SAML provider. + const prevUser = userCredential.user; + const emailCredential = + EmailAuthProvider.credential(email, password); + return linkWithCredential(prevUser, emailCredential) + .then((linkResult) => { + // Sign in with the newly linked credential + const linkCredential = SAMLAuthProvider.credentialFromResult(linkResult); + return signInWithCredential(auth, linkCredential); + }) + .then((signInResult) => { + // Handle sign in of merged user + // ... + }); + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_account_linking_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_create_custom_token.js b/snippets/auth-next/multi-tenancy/multitenant_create_custom_token.js new file mode 100644 index 00000000..1426cf8a --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_create_custom_token.js @@ -0,0 +1,20 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_create_custom_token_modular] +// Ensure you're using a tenant-aware auth instance +const tenantManager = admin.auth().tenantManager(); +const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); + +// Create a custom token in the usual manner +tenantAuth.createCustomToken(uid) + .then((customToken) => { + // Send token back to client + }) + .catch((error) => { + console.log('Error creating custom token:', error); + }); +// [END multitenant_create_custom_token_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_send_emaillink.js b/snippets/auth-next/multi-tenancy/multitenant_send_emaillink.js new file mode 100644 index 00000000..4c4d95c5 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_send_emaillink.js @@ -0,0 +1,23 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_send_emaillink_modular] +import { sendSignInLinkToEmail } from "firebase/auth"; +// Switch to TENANT_ID1 +auth.tenantId = 'TENANT_ID1'; + +sendSignInLinkToEmail(auth, email, actionCodeSettings) + .then(() => { + // The link was successfully sent. Inform the user. + // Save the email locally so you don't need to ask the user for it again + // if they open the link on the same device. + window.localStorage.setItem('emailForSignIn', email); + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_send_emaillink_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_set_tenant.js b/snippets/auth-next/multi-tenancy/multitenant_set_tenant.js new file mode 100644 index 00000000..9510bc5e --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_set_tenant.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_set_tenant_modular] +import { getAuth } from "firebase/auth"; +const auth = getAuth(); +const tenantId = "TENANT_ID1"; +auth.tenantId = tenantId; +// [END multitenant_set_tenant_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_custom_token.js b/snippets/auth-next/multi-tenancy/multitenant_signin_custom_token.js new file mode 100644 index 00000000..b9fa9c58 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_custom_token.js @@ -0,0 +1,16 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_custom_token_modular] +import { signInWithCustomToken } from "firebase/auth"; +auth.tenantId = 'TENANT_ID1'; + +signInWithCustomToken(auth, token) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_custom_token_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_emaillink.js b/snippets/auth-next/multi-tenancy/multitenant_signin_emaillink.js new file mode 100644 index 00000000..0032af1c --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_emaillink.js @@ -0,0 +1,29 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_emaillink_modular] +import { isSignInWithEmailLink, parseActionCodeURL, signInWithEmailLink } from "firebase/auth"; +if (isSignInWithEmailLink(auth, window.location.href)) { + const actionCodeUrl = parseActionCodeURL(window.location.href); + if (actionCodeUrl.tenantId) { + auth.tenantId = actionCodeUrl.tenantId; + } + let email = window.localStorage.getItem('emailForSignIn'); + if (!email) { + // User opened the link on a different device. To prevent session fixation + // attacks, ask the user to provide the associated email again. For example: + email = window.prompt('Please provide your email for confirmation'); + } + // The client SDK will parse the code from the link for you. + signInWithEmailLink(auth, email, window.location.href) + .then((result) => { + // User is signed in. + // tenant ID available in result.user.tenantId. + // Clear email from storage. + window.localStorage.removeItem('emailForSignIn'); + }); +} +// [END multitenant_signin_emaillink_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_password.js b/snippets/auth-next/multi-tenancy/multitenant_signin_password.js new file mode 100644 index 00000000..73642a8d --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_password.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_password_modular] +import { signInWithEmailAndPassword } from "firebase/auth"; +auth.tenantId = 'TENANT_ID'; + +signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_password_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_password_demo.js b/snippets/auth-next/multi-tenancy/multitenant_signin_password_demo.js new file mode 100644 index 00000000..87882773 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_password_demo.js @@ -0,0 +1,33 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_password_demo_modular] +import { signInWithEmailAndPassword, onAuthStateChanged } from "firebase/auth"; +// Switch to TENANT_ID1 +auth.tenantId = 'TENANT_ID1'; + +// Sign in with tenant +signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Switch to 'TENANT_ID2'. + auth.tenantId = 'TENANT_ID2'; + // auth.currentUser still points to the user. + // auth.currentUser.tenantId is 'TENANT_ID1'. + }); + +// You could also get the current user from Auth state observer. +onAuthStateChanged(auth, (user) => { + if (user) { + // User is signed in. + // user.tenantId is set to 'TENANT_ID1'. + } else { + // No user is signed in. + } +}); +// [END multitenant_signin_password_demo_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_saml_popup.js b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_popup.js new file mode 100644 index 00000000..6aa90550 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_popup.js @@ -0,0 +1,25 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_saml_popup_modular] +import { signInWithPopup } from "firebase/auth"; +// Switch to TENANT_ID1. +auth.tenantId = 'TENANT_ID1'; + +// Sign-in with popup. +signInWithPopup(auth, provider) + .then((userCredential) => { + // User is signed in. + const user = userCredential.user; + // user.tenantId is set to 'TENANT_ID1'. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_saml_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signin_saml_redirect.js b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_redirect.js new file mode 100644 index 00000000..d3552a56 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signin_saml_redirect.js @@ -0,0 +1,29 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signin_saml_redirect_modular] +import { signInWithRedirect, getRedirectResult } from "firebase/auth"; +// Switch to TENANT_ID1. +auth.tenantId = 'TENANT_ID1'; + +// Sign-in with redirect. +signInWithRedirect(auth, provider); + +// After the user completes sign-in and returns to the app, you can get +// the sign-in result by calling getRedirectResult. However, if they sign out +// and sign in again with an IdP, no tenant is used. +getRedirectResult(auth) + .then((result) => { + // User is signed in. + // The tenant ID available in result.user.tenantId. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signin_saml_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_signup_password.js b/snippets/auth-next/multi-tenancy/multitenant_signup_password.js new file mode 100644 index 00000000..d89d5edf --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_signup_password.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_signup_password_modular] +import { createUserWithEmailAndPassword } from "firebase/auth"; +auth.tenantId = 'TENANT_ID'; + +createUserWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // User is signed in. + // userCredential.user.tenantId is 'TENANT_ID'. + }).catch((error) => { + // Handle / display error. + // ... + }); +// [END multitenant_signup_password_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_switch_tenant.js b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant.js new file mode 100644 index 00000000..455e4e3b --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_switch_tenant_modular] +// One Auth instance +// Switch to tenant1 +auth.tenantId = "TENANT_ID1"; +// Switch to tenant2 +auth.tenantId = "TENANT_ID2"; +// Switch back to project level IdPs +auth.tenantId = null; +// [END multitenant_switch_tenant_modular] \ No newline at end of file diff --git a/snippets/auth-next/multi-tenancy/multitenant_switch_tenant_multiinstance.js b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant_multiinstance.js new file mode 100644 index 00000000..72550493 --- /dev/null +++ b/snippets/auth-next/multi-tenancy/multitenant_switch_tenant_multiinstance.js @@ -0,0 +1,19 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/multi-tenancy.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START multitenant_switch_tenant_multiinstance_modular] +// Multiple Auth instances +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth"; +const firebaseApp1 = initializeApp(firebaseConfig1, 'app1_for_tenantId1'); +const firebaseApp2 = initializeApp(firebaseConfig2, 'app2_for_tenantId2'); + +const auth1 = getAuth(firebaseApp1); +const auth2 = getAuth(firebaseApp2); + +auth1.tenantId = "TENANT_ID1"; +auth2.tenantId = "TENANT_ID2"; +// [END multitenant_switch_tenant_multiinstance_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_direct_sign_in.js b/snippets/auth-next/oidc/auth_oidc_direct_sign_in.js new file mode 100644 index 00000000..558fd915 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_direct_sign_in.js @@ -0,0 +1,31 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_direct_sign_in_modular] +import { getAuth, OAuthProvider, signInWithCredential } from "firebase/auth"; + +const auth = getAuth(); +const credential = provider.credential({ + idToken: oidcIdToken, +}); +signInWithCredential(auth, credential) + .then((result) => { + // User is signed in. + const newCredential = OAuthProvider.credentialFromResult(result); + // This gives you a new access token for the OIDC provider. You can use it to directly interact with that provider. + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_oidc_direct_sign_in_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_provider_create.js b/snippets/auth-next/oidc/auth_oidc_provider_create.js new file mode 100644 index 00000000..ce1846b9 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_provider_create.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_provider_create_modular] +import { OAuthProvider } from "firebase/auth"; + +const provider = new OAuthProvider("oidc.myProvider"); +// [END auth_oidc_provider_create_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_signin_popup.js b/snippets/auth-next/oidc/auth_oidc_signin_popup.js new file mode 100644 index 00000000..130d617e --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_signin_popup.js @@ -0,0 +1,27 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_signin_popup_modular] +import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_oidc_signin_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_signin_redirect.js b/snippets/auth-next/oidc/auth_oidc_signin_redirect.js new file mode 100644 index 00000000..2038d116 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_signin_redirect.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_signin_redirect_modular] +import { getAuth, signInWithRedirect } from "firebase/auth"; + +const auth = getAuth(); +signInWithRedirect(auth, provider); +// [END auth_oidc_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/oidc/auth_oidc_signin_redirect_result.js b/snippets/auth-next/oidc/auth_oidc_signin_redirect_result.js new file mode 100644 index 00000000..bc76a620 --- /dev/null +++ b/snippets/auth-next/oidc/auth_oidc_signin_redirect_result.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/oidc.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_oidc_signin_redirect_result_modular] +import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +getRedirectResult(auth) + .then((result) => { + // User is signed in. + const credential = OAuthProvider.credentialFromResult(result); + // This gives you an access token for the OIDC provider. You can use it to directly interact with that provider + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = OAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_oidc_signin_redirect_result_modular] \ No newline at end of file diff --git a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js index f6b6893f..7fd16eea 100644 --- a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js +++ b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_invisible.js @@ -8,11 +8,11 @@ import { getAuth, RecaptchaVerifier } from "firebase/auth"; const auth = getAuth(); -window.recaptchaVerifier = new RecaptchaVerifier('sign-in-button', { +window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', { 'size': 'invisible', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. onSignInSubmit(); } -}, auth); +}); // [END auth_phone_recaptcha_verifier_invisible_modular] \ No newline at end of file diff --git a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js index ed56fe99..b57eb37b 100644 --- a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js +++ b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_simple.js @@ -8,5 +8,5 @@ import { getAuth, RecaptchaVerifier } from "firebase/auth"; const auth = getAuth(); -window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {}, auth); +window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {}); // [END auth_phone_recaptcha_verifier_simple_modular] \ No newline at end of file diff --git a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js index c91e6041..42ebbe69 100644 --- a/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js +++ b/snippets/auth-next/phone-auth/auth_phone_recaptcha_verifier_visible.js @@ -8,7 +8,7 @@ import { getAuth, RecaptchaVerifier } from "firebase/auth"; const auth = getAuth(); -window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', { +window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', { 'size': 'normal', 'callback': (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. @@ -18,5 +18,5 @@ window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', { // Response expired. Ask user to solve reCAPTCHA again. // ... } -}, auth); +}); // [END auth_phone_recaptcha_verifier_visible_modular] \ No newline at end of file diff --git a/snippets/auth-next/saml/auth_saml_provider_create.js b/snippets/auth-next/saml/auth_saml_provider_create.js new file mode 100644 index 00000000..e492d490 --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_provider_create.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_provider_create_modular] +import { SAMLAuthProvider } from "firebase/auth"; + +const provider = new SAMLAuthProvider("saml.myProvider"); +// [END auth_saml_provider_create_modular] \ No newline at end of file diff --git a/snippets/auth-next/saml/auth_saml_signin_popup.js b/snippets/auth-next/saml/auth_saml_signin_popup.js new file mode 100644 index 00000000..3a922a9a --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_signin_popup.js @@ -0,0 +1,27 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_signin_popup_modular] +import { getAuth, signInWithPopup, SAMLAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +signInWithPopup(auth, provider) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }).catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_saml_signin_popup_modular] \ No newline at end of file diff --git a/snippets/auth-next/saml/auth_saml_signin_redirect.js b/snippets/auth-next/saml/auth_saml_signin_redirect.js new file mode 100644 index 00000000..619af67f --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_signin_redirect.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_signin_redirect_modular] +import { getAuth, signInWithRedirect } from "firebase/auth"; + +const auth = getAuth(); +signInWithRedirect(auth, provider); +// [END auth_saml_signin_redirect_modular] \ No newline at end of file diff --git a/snippets/auth-next/saml/auth_saml_signin_redirect_result.js b/snippets/auth-next/saml/auth_saml_signin_redirect_result.js new file mode 100644 index 00000000..e4bf73de --- /dev/null +++ b/snippets/auth-next/saml/auth_saml_signin_redirect_result.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/saml.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_saml_signin_redirect_result_modular] +import { getAuth, getRedirectResult, SAMLAuthProvider } from "firebase/auth"; + +const auth = getAuth(); +getRedirectResult(auth) + .then((result) => { + // User is signed in. + // Provider data available from the result.user.getIdToken() + // or from result.user.providerData + }) + .catch((error) => { + // Handle Errors here. + const errorCode = error.code; + const errorMessage = error.message; + // The email of the user's account used. + const email = error.customData.email; + // The AuthCredential type that was used. + const credential = SAMLAuthProvider.credentialFromError(error); + // Handle / display error. + // ... + }); +// [END auth_saml_signin_redirect_result_modular] \ No newline at end of file diff --git a/snippets/auth-next/twitter/auth_twitter_provider_credential.js b/snippets/auth-next/twitter/auth_twitter_provider_credential.js new file mode 100644 index 00000000..e25b369c --- /dev/null +++ b/snippets/auth-next/twitter/auth_twitter_provider_credential.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./auth-next/twitter.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START auth_twitter_provider_credential_modular] +import { TwitterAuthProvider } from "firebase/auth"; + +const credential = TwitterAuthProvider.credential(accessToken, secret); +// [END auth_twitter_provider_credential_modular] \ No newline at end of file diff --git a/snippets/auth-next/twitter/auth_twitter_signin_popup.js b/snippets/auth-next/twitter/auth_twitter_signin_popup.js index a5fb5a95..adb7322e 100644 --- a/snippets/auth-next/twitter/auth_twitter_signin_popup.js +++ b/snippets/auth-next/twitter/auth_twitter_signin_popup.js @@ -18,13 +18,14 @@ signInWithPopup(auth, provider) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... diff --git a/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js b/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js index 53b42c85..357faa4e 100644 --- a/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js +++ b/snippets/auth-next/twitter/auth_twitter_signin_redirect_result.js @@ -19,12 +19,14 @@ getRedirectResult(auth) // The signed-in user info. const user = result.user; + // IdP data available using getAdditionalUserInfo(result) + // ... }).catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // The email of the user's account used. - const email = error.email; + const email = error.customData.email; // The AuthCredential type that was used. const credential = TwitterAuthProvider.credentialFromError(error); // ... diff --git a/snippets/database-next/emulator-suite/rtdb_emulator_connect.js b/snippets/database-next/emulator-suite/rtdb_emulator_connect.js index 4cc268e7..0bd145f6 100644 --- a/snippets/database-next/emulator-suite/rtdb_emulator_connect.js +++ b/snippets/database-next/emulator-suite/rtdb_emulator_connect.js @@ -10,6 +10,6 @@ import { getDatabase, connectDatabaseEmulator } from "firebase/database"; const db = getDatabase(); if (location.hostname === "localhost") { // Point to the RTDB emulator running on localhost. - connectDatabaseEmulator(db, "localhost", 9000); + connectDatabaseEmulator(db, "127.0.0.1", 9000); } // [END rtdb_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/database-next/read-and-write/rtdb_social_listen_star_count.js b/snippets/database-next/read-and-write/rtdb_social_listen_star_count.js index ab520ce6..eb782894 100644 --- a/snippets/database-next/read-and-write/rtdb_social_listen_star_count.js +++ b/snippets/database-next/read-and-write/rtdb_social_listen_star_count.js @@ -5,7 +5,7 @@ // 'npm run snippets'. // [START rtdb_social_listen_star_count_modular] -import { getDatabase, ref, onValue} from "firebase/database"; +import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const starCountRef = ref(db, 'posts/' + postId + '/starCount'); diff --git a/snippets/database-next/read-and-write/rtdb_social_write_fan_out.js b/snippets/database-next/read-and-write/rtdb_social_write_fan_out.js index f787d4bd..783eca2b 100644 --- a/snippets/database-next/read-and-write/rtdb_social_write_fan_out.js +++ b/snippets/database-next/read-and-write/rtdb_social_write_fan_out.js @@ -5,6 +5,8 @@ // 'npm run snippets'. // [START rtdb_social_write_fan_out_modular] +import { getDatabase, ref, child, push, update } from "firebase/database"; + function writeNewPost(uid, username, picture, title, body) { const db = getDatabase(); diff --git a/snippets/firebaseapp-next/firebaseapp/app_default_init_options.js b/snippets/firebaseapp-next/firebaseapp/app_default_init_options.js new file mode 100644 index 00000000..7cebaaf3 --- /dev/null +++ b/snippets/firebaseapp-next/firebaseapp/app_default_init_options.js @@ -0,0 +1,24 @@ +// This snippet file was generated by processing the source file: +// ./firebaseapp-next/firebaseapp.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START app_default_init_options_modular] +import { initializeApp } from "firebase/app"; +import { getStorage } from "firebase/storage"; +import { getFirestore } from "firebase/firestore"; + +// Initialize Firebase with a "default" Firebase project +const defaultProject = initializeApp(firebaseConfig); + +console.log(defaultProject.name); // "[DEFAULT]" + +// Option 1: Access Firebase services via the defaultProject variable +let defaultStorage = getStorage(defaultProject); +let defaultFirestore = getFirestore(defaultProject); + +// Option 2: Access Firebase services using shorthand notation +defaultStorage = getStorage(); +defaultFirestore = getFirestore(); +// [END app_default_init_options_modular] \ No newline at end of file diff --git a/snippets/firebaseapp-next/firebaseapp/app_multi_project_init_options.js b/snippets/firebaseapp-next/firebaseapp/app_multi_project_init_options.js new file mode 100644 index 00000000..415f8813 --- /dev/null +++ b/snippets/firebaseapp-next/firebaseapp/app_multi_project_init_options.js @@ -0,0 +1,28 @@ +// This snippet file was generated by processing the source file: +// ./firebaseapp-next/firebaseapp.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START app_multi_project_init_options_modular] +import { initializeApp, getApp } from "firebase/app"; +import { getStorage } from "firebase/storage"; +import { getFirestore } from "firebase/firestore"; + +// Initialize Firebase with a default Firebase project +initializeApp(firebaseConfig); + +// Initialize Firebase with a second Firebase project +const otherProject = initializeApp(otherProjectFirebaseConfig, "other"); + +console.log(getApp().name); // "[DEFAULT]" +console.log(otherProject.name); // "otherProject" + +// Use the shorthand notation to access the default project's Firebase services +const defaultStorage = getStorage(); +const defaultFirestore = getFirestore(); + +// Use the otherProject variable to access the second project's Firebase services +const otherStorage = getStorage(otherProject); +const otherFirestore = getFirestore(otherProject); +// [END app_multi_project_init_options_modular] \ No newline at end of file diff --git a/snippets/firestore-next/emulator-suite/fs_emulator_connect.js b/snippets/firestore-next/emulator-suite/fs_emulator_connect.js index 7e31fcfd..d70fbb68 100644 --- a/snippets/firestore-next/emulator-suite/fs_emulator_connect.js +++ b/snippets/firestore-next/emulator-suite/fs_emulator_connect.js @@ -9,5 +9,5 @@ import { getFirestore, connectFirestoreEmulator } from "firebase/firestore"; // firebaseApps previously initialized using initializeApp() const db = getFirestore(); -connectFirestoreEmulator(db, 'localhost', 8080); +connectFirestoreEmulator(db, '127.0.0.1', 8080); // [END fs_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/count_aggregate_collection.js b/snippets/firestore-next/test-firestore/count_aggregate_collection.js new file mode 100644 index 00000000..7dca7e37 --- /dev/null +++ b/snippets/firestore-next/test-firestore/count_aggregate_collection.js @@ -0,0 +1,11 @@ +// This snippet file was generated by processing the source file: +// ./firestore-next/test.firestore.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START count_aggregate_collection_modular] +const coll = collection(db, "cities"); +const snapshot = await getCountFromServer(coll); +console.log('count: ', snapshot.data().count); +// [END count_aggregate_collection_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/count_aggregate_query.js b/snippets/firestore-next/test-firestore/count_aggregate_query.js new file mode 100644 index 00000000..37a27458 --- /dev/null +++ b/snippets/firestore-next/test-firestore/count_aggregate_query.js @@ -0,0 +1,12 @@ +// This snippet file was generated by processing the source file: +// ./firestore-next/test.firestore.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START count_aggregate_query_modular] +const coll = collection(db, "cities"); +const q = query(coll, where("state", "==", "CA")); +const snapshot = await getCountFromServer(q); +console.log('count: ', snapshot.data().count); +// [END count_aggregate_query_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/firestore_query_subcollection.js b/snippets/firestore-next/test-firestore/firestore_query_subcollection.js new file mode 100644 index 00000000..76a1b847 --- /dev/null +++ b/snippets/firestore-next/test-firestore/firestore_query_subcollection.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./firestore-next/test.firestore.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START firestore_query_subcollection_modular] +import { collection, getDocs } from "firebase/firestore"; +// Query a reference to a subcollection +const querySnapshot = await getDocs(collection(db, "cities", "SF", "landmarks")); +querySnapshot.forEach((doc) => { + // doc.data() is never undefined for query doc snapshots + console.log(doc.id, " => ", doc.data()); +}); +// [END firestore_query_subcollection_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js b/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js index f4f62178..f06ea0f8 100644 --- a/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js +++ b/snippets/firestore-next/test-firestore/fs_collection_group_query_data_setup.js @@ -5,48 +5,48 @@ // 'npm run snippets'. // [START fs_collection_group_query_data_setup_modular] -import { collection, doc, setDoc } from "firebase/firestore"; +import { collection, addDoc } from "firebase/firestore"; const citiesRef = collection(db, 'cities'); await Promise.all([ - setDoc(doc(citiesRef, 'SF', 'landmarks'), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Golden Gate Bridge', type: 'bridge' }), - setDoc(doc(citiesRef, 'SF', 'landmarks'), { + addDoc(collection(citiesRef, 'SF', 'landmarks'), { name: 'Legion of Honor', type: 'museum' }), - setDoc(doc(citiesRef, 'LA', 'landmarks'), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'Griffith Park', type: 'park' }), - setDoc(doc(citiesRef, 'LA', 'landmarks'), { + addDoc(collection(citiesRef, 'LA', 'landmarks'), { name: 'The Getty', type: 'museum' }), - setDoc(doc(citiesRef, 'DC', 'landmarks'), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'Lincoln Memorial', type: 'memorial' }), - setDoc(doc(citiesRef, 'DC', 'landmarks'), { + addDoc(collection(citiesRef, 'DC', 'landmarks'), { name: 'National Air and Space Museum', type: 'museum' }), - setDoc(doc(citiesRef, 'TOK', 'landmarks'), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'Ueno Park', type: 'park' }), - setDoc(doc(citiesRef, 'TOK', 'landmarks'), { + addDoc(collection(citiesRef, 'TOK', 'landmarks'), { name: 'National Museum of Nature and Science', type: 'museum' }), - setDoc(doc(citiesRef, 'BJ', 'landmarks'), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Jingshan Park', type: 'park' }), - setDoc(doc(citiesRef, 'BJ', 'landmarks'), { + addDoc(collection(citiesRef, 'BJ', 'landmarks'), { name: 'Beijing Ancient Observatory', type: 'museum' }) diff --git a/snippets/firestore-next/test-firestore/get_document.js b/snippets/firestore-next/test-firestore/get_document.js index 4cfbaaf6..1653b61a 100644 --- a/snippets/firestore-next/test-firestore/get_document.js +++ b/snippets/firestore-next/test-firestore/get_document.js @@ -13,7 +13,7 @@ const docSnap = await getDoc(docRef); if (docSnap.exists()) { console.log("Document data:", docSnap.data()); } else { - // doc.data() will be undefined in this case + // docSnap.data() will be undefined in this case console.log("No such document!"); } // [END get_document_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/in_filter_with_array.js b/snippets/firestore-next/test-firestore/in_filter_with_array.js index ebe6f18b..190e9dfe 100644 --- a/snippets/firestore-next/test-firestore/in_filter_with_array.js +++ b/snippets/firestore-next/test-firestore/in_filter_with_array.js @@ -7,5 +7,5 @@ // [START in_filter_with_array_modular] import { query, where } from "firebase/firestore"; -const q = query(citiesRef, where('regions', 'in', [['west_coast', 'east_coast']])); +const q = query(citiesRef, where('regions', 'in', [['west_coast'], ['east_coast']])); // [END in_filter_with_array_modular] \ No newline at end of file diff --git a/snippets/firestore-next/test-firestore/start_doc.js b/snippets/firestore-next/test-firestore/start_doc.js index e75c7984..88448fcd 100644 --- a/snippets/firestore-next/test-firestore/start_doc.js +++ b/snippets/firestore-next/test-firestore/start_doc.js @@ -11,6 +11,6 @@ const citiesRef = collection(db, "cities"); const docSnap = await getDoc(doc(citiesRef, "SF")); // Get all cities with a population bigger than San Francisco -const biggerThanSf = query(citiesRef, orderBy("popuation"), startAt(docSnap)); +const biggerThanSf = query(citiesRef, orderBy("population"), startAt(docSnap)); // ... // [END start_doc_modular] \ No newline at end of file diff --git a/snippets/functions-next/emulator-suite/fb_functions_emulator_connect.js b/snippets/functions-next/emulator-suite/fb_functions_emulator_connect.js index 9b186fc2..835a2c60 100644 --- a/snippets/functions-next/emulator-suite/fb_functions_emulator_connect.js +++ b/snippets/functions-next/emulator-suite/fb_functions_emulator_connect.js @@ -9,5 +9,5 @@ import { getApp } from "firebase/app"; import { getFunctions, connectFunctionsEmulator } from "firebase/functions"; const functions = getFunctions(getApp()); -connectFunctionsEmulator(functions, "localhost", 5001); +connectFunctionsEmulator(functions, "127.0.0.1", 5001); // [END fb_functions_emulator_connect_modular] \ No newline at end of file diff --git a/snippets/messaging-next/service-worker/messaging_init_in_sw.js b/snippets/messaging-next/service-worker/messaging_init_in_sw.js index abce8e1d..42f0f526 100644 --- a/snippets/messaging-next/service-worker/messaging_init_in_sw.js +++ b/snippets/messaging-next/service-worker/messaging_init_in_sw.js @@ -6,7 +6,7 @@ // [START messaging_init_in_sw_modular] import { initializeApp } from "firebase/app"; -import { getMessaging } from "firebase/messaging"; +import { getMessaging } from "firebase/messaging/sw"; // Initialize the Firebase app in the service worker by passing in // your app's Firebase config object. diff --git a/snippets/messaging-next/service-worker/messaging_on_background_message.js b/snippets/messaging-next/service-worker/messaging_on_background_message.js index b7f65b53..79c17eea 100644 --- a/snippets/messaging-next/service-worker/messaging_on_background_message.js +++ b/snippets/messaging-next/service-worker/messaging_on_background_message.js @@ -5,7 +5,7 @@ // 'npm run snippets'. // [START messaging_on_background_message_modular] -import { getMessaging } from "firebase/messaging"; +import { getMessaging } from "firebase/messaging/sw"; import { onBackgroundMessage } from "firebase/messaging/sw"; const messaging = getMessaging(); diff --git a/snippets/perf-next/index/perf_import.js b/snippets/perf-next/index/perf_import.js new file mode 100644 index 00000000..326afe91 --- /dev/null +++ b/snippets/perf-next/index/perf_import.js @@ -0,0 +1,9 @@ +// This snippet file was generated by processing the source file: +// ./perf-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START perf_import_modular] +import { getPerformance } from "firebase/performance"; +// [END perf_import_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_import_app.js b/snippets/perf-next/index/perf_import_app.js new file mode 100644 index 00000000..c2b640b9 --- /dev/null +++ b/snippets/perf-next/index/perf_import_app.js @@ -0,0 +1,9 @@ +// This snippet file was generated by processing the source file: +// ./perf-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START perf_import_app_modular] +import { initializeApp } from "firebase/app"; +// [END perf_import_app_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_initialize.js b/snippets/perf-next/index/perf_initialize_app.js similarity index 51% rename from snippets/perf-next/index/perf_initialize.js rename to snippets/perf-next/index/perf_initialize_app.js index 3b87e9c8..94e0c966 100644 --- a/snippets/perf-next/index/perf_initialize.js +++ b/snippets/perf-next/index/perf_initialize_app.js @@ -4,19 +4,13 @@ // To update the snippets in this file, edit the source and then run // 'npm run snippets'. -// [START perf_initialize_modular] -import { initializeApp } from "firebase/app"; -import { getPerformance } from "firebase/performance"; - +// [START perf_initialize_app_modular] // TODO: Replace the following with your app's Firebase project configuration -// See: https://firebase.google.com/docs/web/setup#config-object +// See: https://firebase.google.com/docs/web/learn-more#config-object const firebaseConfig = { // ... }; // Initialize Firebase const app = initializeApp(firebaseConfig); - -// Initialize Performance Monitoring and get a reference to the service -const perf = getPerformance(app); -// [END perf_initialize_modular] \ No newline at end of file +// [END perf_initialize_app_modular] \ No newline at end of file diff --git a/snippets/perf-next/index/perf_singleton.js b/snippets/perf-next/index/perf_singleton.js new file mode 100644 index 00000000..e070b52b --- /dev/null +++ b/snippets/perf-next/index/perf_singleton.js @@ -0,0 +1,10 @@ +// This snippet file was generated by processing the source file: +// ./perf-next/index.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START perf_singleton_modular] +// Initialize Performance Monitoring and get a reference to the service +const perf = getPerformance(app); +// [END perf_singleton_modular] \ No newline at end of file diff --git a/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js b/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js index 131976c5..77aa9f45 100644 --- a/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js +++ b/snippets/remoteconfig-next/index/rc_set_minimum_fetch_time.js @@ -5,5 +5,6 @@ // 'npm run snippets'. // [START rc_set_minimum_fetch_time_modular] +// The default and recommended production fetch interval for Remote Config is 12 hours remoteConfig.settings.minimumFetchIntervalMillis = 3600000; // [END rc_set_minimum_fetch_time_modular] \ No newline at end of file diff --git a/snippets/storage-next/emulator-suite/storage_emulator_connect.js b/snippets/storage-next/emulator-suite/storage_emulator_connect.js new file mode 100644 index 00000000..4b247d17 --- /dev/null +++ b/snippets/storage-next/emulator-suite/storage_emulator_connect.js @@ -0,0 +1,15 @@ +// This snippet file was generated by processing the source file: +// ./storage-next/emulator-suite.js +// +// To update the snippets in this file, edit the source and then run +// 'npm run snippets'. + +// [START storage_emulator_connect_modular] +import { getStorage, connectStorageEmulator } from "firebase/storage"; + +const storage = getStorage(); +if (location.hostname === "localhost") { + // Point to the Storage emulator running on localhost. + connectStorageEmulator(storage, "127.0.0.1", 9199); +} +// [END storage_emulator_connect_modular] \ No newline at end of file diff --git a/storage-next/emulator-suite.js b/storage-next/emulator-suite.js new file mode 100644 index 00000000..78891a4f --- /dev/null +++ b/storage-next/emulator-suite.js @@ -0,0 +1,14 @@ +// [SNIPPET_REGISTRY disabled] +// [SNIPPETS_SEPARATION enabled] + +function onDocumentReady() { + // [START storage_emulator_connect] + const { getStorage, connectStorageEmulator } = require("firebase/storage"); + + const storage = getStorage(); + if (location.hostname === "localhost") { + // Point to the Storage emulator running on localhost. + connectStorageEmulator(storage, "127.0.0.1", 9199); + } + // [END storage_emulator_connect] +} diff --git a/storage-next/package.json b/storage-next/package.json index 6aca1112..b1c449ab 100644 --- a/storage-next/package.json +++ b/storage-next/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^9.0.0-beta.8" + "firebase": "^10.0.0" } } diff --git a/storage/emulator-suite.js b/storage/emulator-suite.js new file mode 100644 index 00000000..be1f2dd4 --- /dev/null +++ b/storage/emulator-suite.js @@ -0,0 +1,16 @@ +// These samples are intended for Web so this import would normally be +// done in HTML however using modules here is more convenient for +// ensuring sample correctness offline. +import firebase from "firebase/app"; +import "firebase/storage"; + +function onDocumentReady() { + // [START storage_emulator_connect] + var storage = firebase.storage(); + if (location.hostname === "localhost") { + // Point to the Storage emulator running on localhost. + storage.useEmulator("127.0.0.1", 9199); + } + // [END storage_emulator_connect] +} + diff --git a/storage/package.json b/storage/package.json index 18190f7a..e27166e7 100644 --- a/storage/package.json +++ b/storage/package.json @@ -6,6 +6,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase": "^8.8.1" + "firebase": "^8.10.0" } }