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