diff --git a/analytics-next/index.js b/analytics-next/index.js
index 510fa758..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]
}
diff --git a/analytics-next/package.json b/analytics-next/package.json
index d0955d16..ee4e36ff 100644
--- a/analytics-next/package.json
+++ b/analytics-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "firebase": "^10.0.0"
}
}
diff --git a/appcheck-next/package.json b/appcheck-next/package.json
index 7c84b7df..e863723e 100644
--- a/appcheck-next/package.json
+++ b/appcheck-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "firebase": "^10.0.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/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 53d964a2..8d43bad1 100644
--- a/auth-next/package.json
+++ b/auth-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "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 a6827027..b4b13f01 100644
--- a/auth/package.json
+++ b/auth/package.json
@@ -7,6 +7,7 @@
"license": "Apache 2.0",
"dependencies": {
"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 175d6c63..eb16e2d5 100644
--- a/database-next/package.json
+++ b/database-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "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/firebaseapp-next/package.json b/firebaseapp-next/package.json
index 88dd8954..13cc74cd 100644
--- a/firebaseapp-next/package.json
+++ b/firebaseapp-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "firebase": "^10.0.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 2c95f580..ef3b8708 100644
--- a/firestore-next/package.json
+++ b/firestore-next/package.json
@@ -6,7 +6,7 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0",
+ "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 ddc3c44d..3599ca13 100644
--- a/firestore/index.html
+++ b/firestore/index.html
@@ -12,8 +12,8 @@
-
-
+
+
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 4ddfe8c3..14f097ee 100644
--- a/functions-next/package.json
+++ b/functions-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "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/messaging-next/package.json b/messaging-next/package.json
index fe28f50e..e4887a2a 100644
--- a/messaging-next/package.json
+++ b/messaging-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "firebase": "^10.0.0"
}
}
diff --git a/messaging-next/service-worker.js b/messaging-next/service-worker.js
index a81a7c18..55f07524 100644
--- a/messaging-next/service-worker.js
+++ b/messaging-next/service-worker.js
@@ -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/service-worker.js b/messaging/service-worker.js
index 3b2f7de0..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.10.0/firebase-app.js');
- importScripts('https://www.gstatic.com/firebasejs/8.10.0/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/perf-next/package.json b/perf-next/package.json
index 69cf753b..688f6db0 100644
--- a/perf-next/package.json
+++ b/perf-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "firebase": "^10.0.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 8a072847..952b1540 100644
--- a/remoteconfig-next/package.json
+++ b/remoteconfig-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "firebase": "^10.0.0"
}
}
diff --git a/scripts/separate-snippets.ts b/scripts/separate-snippets.ts
index ff93a58f..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 = [
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/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/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/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_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/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 fbce56ec..b1c449ab 100644
--- a/storage-next/package.json
+++ b/storage-next/package.json
@@ -6,6 +6,6 @@
},
"license": "Apache-2.0",
"dependencies": {
- "firebase": "^9.1.0"
+ "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]
+}
+