1+ // [SNIPPET_REGISTRY disabled]
2+ // [SNIPPETS_SEPARATION enabled]
3+
4+ function setTenant ( ) {
5+ // [START multitenant_set_tenant]
6+ const { getAuth } = require ( "firebase/auth" ) ;
7+ const auth = getAuth ( ) ;
8+ const tenantId = "TENANT_ID1" ;
9+ auth . tenantId = tenantId ;
10+ // [END multitenant_set_tenant]
11+ }
12+
13+ function switchTenantSingleAuth ( auth ) {
14+ // [START multitenant_switch_tenant]
15+ // One Auth instance
16+ // Switch to tenant1
17+ auth . tenantId = "TENANT_ID1" ;
18+ // Switch to tenant2
19+ auth . tenantId = "TENANT_ID2" ;
20+ // Switch back to project level IdPs
21+ auth . tenantId = null ;
22+ // [END multitenant_switch_tenant]
23+ }
24+
25+ function switchTenantMultiAuth ( firebaseConfig1 , firebaseConfig2 ) {
26+ // [START multitenant_switch_tenant_multiinstance]
27+ // Multiple Auth instances
28+ const { initializeApp } = require ( "firebase/app" ) ;
29+ const { getAuth } = require ( "firebase/auth" ) ;
30+ const firebaseApp1 = initializeApp ( firebaseConfig1 , 'app1_for_tenantId1' ) ;
31+ const firebaseApp2 = initializeApp ( firebaseConfig2 , 'app2_for_tenantId2' ) ;
32+
33+ const auth1 = getAuth ( firebaseApp1 ) ;
34+ const auth2 = getAuth ( firebaseApp2 ) ;
35+
36+ auth1 . tenantId = "TENANT_ID1" ;
37+ auth2 . tenantId = "TENANT_ID2" ;
38+ // [END multitenant_switch_tenant_multiinstance]
39+ }
40+
41+ function passwordSignInWithTenantDemo ( auth , email , password ) {
42+ // [START multitenant_signin_password_demo]
43+ const { signInWithEmailAndPassword, onAuthStateChanged } = require ( "firebase/auth" ) ;
44+ // Switch to TENANT_ID1
45+ auth . tenantId = 'TENANT_ID1' ;
46+
47+ // Sign in with tenant
48+ signInWithEmailAndPassword ( auth , email , password )
49+ . then ( ( userCredential ) => {
50+ // User is signed in.
51+ const user = userCredential . user ;
52+ // user.tenantId is set to 'TENANT_ID1'.
53+ // Switch to 'TENANT_ID2'.
54+ auth . tenantId = 'TENANT_ID2' ;
55+ // auth.currentUser still points to the user.
56+ // auth.currentUser.tenantId is 'TENANT_ID1'.
57+ } ) ;
58+
59+ // You could also get the current user from Auth state observer.
60+ onAuthStateChanged ( auth , ( user ) => {
61+ if ( user ) {
62+ // User is signed in.
63+ // user.tenantId is set to 'TENANT_ID1'.
64+ } else {
65+ // No user is signed in.
66+ }
67+ } ) ;
68+ // [END multitenant_signin_password_demo]
69+ }
70+
71+ function signUpWithTenant ( auth , email , password ) {
72+ // [START multitenant_signup_password]
73+ const { createUserWithEmailAndPassword } = require ( "firebase/auth" ) ;
74+ auth . tenantId = 'TENANT_ID' ;
75+
76+ createUserWithEmailAndPassword ( auth , email , password )
77+ . then ( ( userCredential ) => {
78+ // User is signed in.
79+ // userCredential.user.tenantId is 'TENANT_ID'.
80+ } ) . catch ( ( error ) => {
81+ // Handle / display error.
82+ // ...
83+ } ) ;
84+ // [END multitenant_signup_password]
85+ }
86+
87+
88+ function passwordSignInWithTenant ( auth , email , password ) {
89+ // [START multitenant_signin_password]
90+ const { signInWithEmailAndPassword } = require ( "firebase/auth" ) ;
91+ auth . tenantId = 'TENANT_ID' ;
92+
93+ signInWithEmailAndPassword ( auth , email , password )
94+ . then ( ( userCredential ) => {
95+ // User is signed in.
96+ // userCredential.user.tenantId is 'TENANT_ID'.
97+ } ) . catch ( ( error ) => {
98+ // Handle / display error.
99+ // ...
100+ } ) ;
101+ // [END multitenant_signin_password]
102+ }
103+
104+ function samlSignInPopupTenant ( auth , provider ) {
105+ // [START multitenant_signin_saml_popup]
106+ const { signInWithPopup } = require ( "firebase/auth" ) ;
107+ // Switch to TENANT_ID1.
108+ auth . tenantId = 'TENANT_ID1' ;
109+
110+ // Sign-in with popup.
111+ signInWithPopup ( auth , provider )
112+ . then ( ( userCredential ) => {
113+ // User is signed in.
114+ const user = userCredential . user ;
115+ // user.tenantId is set to 'TENANT_ID1'.
116+ // Provider data available from the result.user.getIdToken()
117+ // or from result.user.providerData
118+ } )
119+ . catch ( ( error ) => {
120+ // Handle / display error.
121+ // ...
122+ } ) ;
123+ // [END multitenant_signin_saml_popup]
124+ }
125+
126+ function samlSignInRedirectTenant ( auth , provider ) {
127+ // [START multitenant_signin_saml_redirect]
128+ const { signInWithRedirect, getRedirectResult } = require ( "firebase/auth" ) ;
129+ // Switch to TENANT_ID1.
130+ auth . tenantId = 'TENANT_ID1' ;
131+
132+ // Sign-in with redirect.
133+ signInWithRedirect ( auth , provider ) ;
134+
135+ // After the user completes sign-in and returns to the app, you can get
136+ // the sign-in result by calling getRedirectResult. However, if they sign out
137+ // and sign in again with an IdP, no tenant is used.
138+ getRedirectResult ( auth )
139+ . then ( ( result ) => {
140+ // User is signed in.
141+ // The tenant ID available in result.user.tenantId.
142+ // Provider data available from the result.user.getIdToken()
143+ // or from result.user.providerData
144+ } )
145+ . catch ( ( error ) => {
146+ // Handle / display error.
147+ // ...
148+ } ) ;
149+ // [END multitenant_signin_saml_redirect]
150+ }
151+
152+ function sendSignInLinkToEmailTenant ( auth , email , actionCodeSettings ) {
153+ // [START multitenant_send_emaillink]
154+ const { sendSignInLinkToEmail } = require ( "firebase/auth" ) ;
155+ // Switch to TENANT_ID1
156+ auth . tenantId = 'TENANT_ID1' ;
157+
158+ sendSignInLinkToEmail ( auth , email , actionCodeSettings )
159+ . then ( ( ) => {
160+ // The link was successfully sent. Inform the user.
161+ // Save the email locally so you don't need to ask the user for it again
162+ // if they open the link on the same device.
163+ window . localStorage . setItem ( 'emailForSignIn' , email ) ;
164+ } )
165+ . catch ( ( error ) => {
166+ // Handle / display error.
167+ // ...
168+ } ) ;
169+ // [END multitenant_send_emaillink]
170+ }
171+
172+ function signInWithEmailLinkTenant ( auth ) {
173+ // [START multitenant_signin_emaillink]
174+ const { isSignInWithEmailLink, parseActionCodeURL, signInWithEmailLink } = require ( "firebase/auth" ) ;
175+ if ( isSignInWithEmailLink ( auth , window . location . href ) ) {
176+ const actionCodeUrl = parseActionCodeURL ( window . location . href ) ;
177+ if ( actionCodeUrl . tenantId ) {
178+ auth . tenantId = actionCodeUrl . tenantId ;
179+ }
180+ let email = window . localStorage . getItem ( 'emailForSignIn' ) ;
181+ if ( ! email ) {
182+ // User opened the link on a different device. To prevent session fixation
183+ // attacks, ask the user to provide the associated email again. For example:
184+ email = window . prompt ( 'Please provide your email for confirmation' ) ;
185+ }
186+ // The client SDK will parse the code from the link for you.
187+ signInWithEmailLink ( auth , email , window . location . href )
188+ . then ( ( result ) => {
189+ // User is signed in.
190+ // tenant ID available in result.user.tenantId.
191+ // Clear email from storage.
192+ window . localStorage . removeItem ( 'emailForSignIn' ) ;
193+ } ) ;
194+ }
195+ // [END multitenant_signin_emaillink]
196+ }
197+
198+ // Same as the code in auth/ since this is the admin SDK.
199+ function createCustomTokenTenant ( admin , uid ) {
200+ // [START multitenant_create_custom_token]
201+ // Ensure you're using a tenant-aware auth instance
202+ const tenantManager = admin . auth ( ) . tenantManager ( ) ;
203+ const tenantAuth = tenantManager . authForTenant ( 'TENANT_ID1' ) ;
204+
205+ // Create a custom token in the usual manner
206+ tenantAuth . createCustomToken ( uid )
207+ . then ( ( customToken ) => {
208+ // Send token back to client
209+ } )
210+ . catch ( ( error ) => {
211+ console . log ( 'Error creating custom token:' , error ) ;
212+ } ) ;
213+ // [END multitenant_create_custom_token]
214+ }
215+
216+ function signInWithCustomTokenTenant ( auth , token ) {
217+ // [START multitenant_signin_custom_token]
218+ const { signInWithCustomToken } = require ( "firebase/auth" ) ;
219+ auth . tenantId = 'TENANT_ID1' ;
220+
221+ signInWithCustomToken ( auth , token )
222+ . catch ( ( error ) => {
223+ // Handle / display error.
224+ // ...
225+ } ) ;
226+ // [END multitenant_signin_custom_token]
227+ }
228+
229+ function linkAccountTenant ( auth , provider , email , password ) {
230+ // [START multitenant_account_linking]
231+ const { signInWithPopup, EmailAuthProvider, linkWithCredential, SAMLAuthProvider, signInWithCredential } = require ( "firebase/auth" ) ;
232+ // Switch to TENANT_ID1
233+ auth . tenantId = 'TENANT_ID1' ;
234+
235+ // Sign-in with popup
236+ signInWithPopup ( auth , provider )
237+ . then ( ( userCredential ) => {
238+ // Existing user with e.g. SAML provider.
239+ const prevUser = userCredential . user ;
240+ const emailCredential =
241+ EmailAuthProvider . credential ( email , password ) ;
242+ return linkWithCredential ( prevUser , emailCredential )
243+ . then ( ( linkResult ) => {
244+ // Sign in with the newly linked credential
245+ const linkCredential = SAMLAuthProvider . credentialFromResult ( linkResult ) ;
246+ return signInWithCredential ( auth , linkCredential ) ;
247+ } )
248+ . then ( ( signInResult ) => {
249+ // Handle sign in of merged user
250+ // ...
251+ } ) ;
252+ } )
253+ . catch ( ( error ) => {
254+ // Handle / display error.
255+ // ...
256+ } ) ;
257+ // [END multitenant_account_linking]
258+ }
259+
260+ function accountExistsPopupTenant ( auth , samlProvider , googleProvider , goToApp ) {
261+ // [START multitenant_account_exists_popup]
262+ const { signInWithPopup, fetchSignInMethodsForEmail, linkWithCredential } = require ( "firebase/auth" ) ;
263+ // Step 1.
264+ // User tries to sign in to the SAML provider in that tenant.
265+ auth . tenantId = 'TENANT_ID' ;
266+ signInWithPopup ( auth , samlProvider )
267+ . catch ( ( error ) => {
268+ // An error happened.
269+ if ( error . code === 'auth/account-exists-with-different-credential' ) {
270+ // Step 2.
271+ // User's email already exists.
272+ // The pending SAML credential.
273+ const pendingCred = error . credential ;
274+ // The credential's tenantId if needed: error.tenantId
275+ // The provider account's email address.
276+ const email = error . email ;
277+ // Get sign-in methods for this email.
278+ fetchSignInMethodsForEmail ( email , auth )
279+ . then ( ( methods ) => {
280+ // Step 3.
281+ // Ask the user to sign in with existing Google account.
282+ if ( methods [ 0 ] == 'google.com' ) {
283+ signInWithPopup ( auth , googleProvider )
284+ . then ( ( result ) => {
285+ // Step 4
286+ // Link the SAML AuthCredential to the existing user.
287+ linkWithCredential ( result . user , pendingCred )
288+ . then ( ( linkResult ) => {
289+ // SAML account successfully linked to the existing
290+ // user.
291+ goToApp ( ) ;
292+ } ) ;
293+ } ) ;
294+ }
295+ } ) ;
296+ }
297+ } ) ;
298+ // [END multitenant_account_exists_popup]
299+ }
300+
301+ function accountExistsRedirectTenant ( auth , samlProvider , googleProvider , goToApp ) {
302+ // [START multitenant_account_exists_redirect]
303+ const { signInWithRedirect, getRedirectResult, fetchSignInMethodsForEmail, linkWithCredential } = require ( "firebase/auth" ) ;
304+ // Step 1.
305+ // User tries to sign in to SAML provider.
306+ auth . tenantId = 'TENANT_ID' ;
307+ signInWithRedirect ( auth , samlProvider ) ;
308+ var pendingCred ;
309+ // Redirect back from SAML IDP. auth.tenantId is null after redirecting.
310+ getRedirectResult ( auth ) . catch ( ( error ) => {
311+ if ( error . code === 'auth/account-exists-with-different-credential' ) {
312+ // Step 2.
313+ // User's email already exists.
314+ const tenantId = error . tenantId ;
315+ // The pending SAML credential.
316+ pendingCred = error . credential ;
317+ // The provider account's email address.
318+ const email = error . email ;
319+ // Need to set the tenant ID again as the page was reloaded and the
320+ // previous setting was reset.
321+ auth . tenantId = tenantId ;
322+ // Get sign-in methods for this email.
323+ fetchSignInMethodsForEmail ( auth , email )
324+ . then ( ( methods ) => {
325+ // Step 3.
326+ // Ask the user to sign in with existing Google account.
327+ if ( methods [ 0 ] == 'google.com' ) {
328+ signInWithRedirect ( auth , googleProvider ) ;
329+ }
330+ } ) ;
331+ }
332+ } ) ;
333+
334+ // Redirect back from Google. auth.tenantId is null after redirecting.
335+ getRedirectResult ( auth ) . then ( ( result ) => {
336+ // Step 4
337+ // Link the SAML AuthCredential to the existing user.
338+ // result.user.tenantId is 'TENANT_ID'.
339+ linkWithCredential ( result . user , pendingCred )
340+ . then ( ( linkResult ) => {
341+ // SAML account successfully linked to the existing
342+ // user.
343+ goToApp ( ) ;
344+ } ) ;
345+ } ) ;
346+ // [END multitenant_account_exists_redirect]
347+ }
0 commit comments