Skip to content

Commit 5b7d7ef

Browse files
authored
[SeverApp] Restrict certain auth operations (#8015)
Updates FirebaseServerApp implementation in Auth to prevent operations that would change the currently logged in user. The user should be that of the authIdToken provided to FirebaseServerApp only. Note: some of the method implementations currently reside in browser-only files. I added safe guards to these methods even though FirebaseServerApp is not supported in browser enviornments. These guards protect us in case the methods are later adapted to other environments and/or migrated to other files that are not browser-only. The changes to the browser implementations produce little overhead, so I thought that safety first was the correct call here.
1 parent 92c655a commit 5b7d7ef

File tree

18 files changed

+377
-47
lines changed

18 files changed

+377
-47
lines changed

docs-devsite/auth.auth.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ auth.setPersistence(browserSessionPersistence);
265265

266266
Signs out the current user. This does not automatically revoke the user's ID token.
267267

268+
This method is not supported by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
269+
268270
<b>Signature:</b>
269271

270272
```typescript

docs-devsite/auth.md

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,8 @@ On successful creation of the user account, this user will also be signed in to
381381

382382
User account creation can fail if the account already exists or the password is invalid.
383383

384+
This method is not supported on [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
385+
384386
Note: The email address acts as a unique identifier for the user and enables an email-based password reset. This function will create a new user account and set the initial user password.
385387

386388
<b>Signature:</b>
@@ -451,7 +453,7 @@ Returns a [UserCredential](./auth.usercredential.md#usercredential_interface) fr
451453

452454
If sign-in succeeded, returns the signed in user. If sign-in was unsuccessful, fails with an error. If no redirect operation was called, returns `null`<!-- -->.
453455

454-
This method does not work in a Node.js environment.
456+
This method does not work in a Node.js environment or with [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
455457

456458
<b>Signature:</b>
457459

@@ -728,7 +730,7 @@ Changes the type of persistence on the [Auth](./auth.auth.md#auth_interface) ins
728730

729731
This makes it easy for a user signing in to specify whether their session should be remembered or not. It also makes it easier to never persist the `Auth` state for applications that are shared by other users or have sensitive data.
730732

731-
This method does not work in a Node.js environment.
733+
This method does not work in a Node.js environment or with [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
732734

733735
<b>Signature:</b>
734736

@@ -763,6 +765,8 @@ Asynchronously signs in as an anonymous user.
763765

764766
If there is already an anonymous user signed in, that user will be returned; otherwise, a new anonymous user identity will be created and returned.
765767

768+
This method is not supported by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
769+
766770
<b>Signature:</b>
767771

768772
```typescript
@@ -785,6 +789,8 @@ Asynchronously signs in with the given credentials.
785789

786790
An [AuthProvider](./auth.authprovider.md#authprovider_interface) can be used to generate the credential.
787791

792+
This method is not supported by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
793+
788794
<b>Signature:</b>
789795

790796
```typescript
@@ -810,6 +816,8 @@ Custom tokens are used to integrate Firebase Auth with existing auth systems, an
810816

811817
Fails with an error if the token is invalid, expired, or not accepted by the Firebase Auth service.
812818

819+
This method is not supported by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
820+
813821
<b>Signature:</b>
814822

815823
```typescript
@@ -833,6 +841,8 @@ Asynchronously signs in using an email and password.
833841

834842
Fails with an error if the email address and password do not match. When \[Email Enumeration Protection\](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled, this method fails with "auth/invalid-credential" in case of an invalid email/password.
835843

844+
This method is not supported on [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
845+
836846
Note: The user's password is NOT the password used to access the user's email account. The email address serves as a unique identifier for the user, and the password is used to access the user's account in your Firebase project. See also: [createUserWithEmailAndPassword()](./auth.md#createuserwithemailandpassword_21ad33b)<!-- -->.
837847

838848
<b>Signature:</b>
@@ -861,6 +871,8 @@ If no link is passed, the link is inferred from the current URL.
861871

862872
Fails with an error if the email address is invalid or OTP in email link expires.
863873

874+
This method is not supported by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
875+
864876
Note: Confirm the link is a sign-in email link before calling this method firebase.auth.Auth.isSignInWithEmailLink.
865877

866878
<b>Signature:</b>
@@ -913,7 +925,7 @@ This method sends a code via SMS to the given phone number, and returns a [Confi
913925

914926
For abuse prevention, this method also requires a [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface)<!-- -->. This SDK includes a reCAPTCHA-based implementation, [RecaptchaVerifier](./auth.recaptchaverifier.md#recaptchaverifier_class)<!-- -->. This function can work on other platforms that do not support the [RecaptchaVerifier](./auth.recaptchaverifier.md#recaptchaverifier_class) (like React Native), but you need to use a third-party [ApplicationVerifier](./auth.applicationverifier.md#applicationverifier_interface) implementation.
915927

916-
This method does not work in a Node.js environment.
928+
This method does not work in a Node.js environment or with [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
917929

918930
<b>Signature:</b>
919931

@@ -951,7 +963,7 @@ Authenticates a Firebase client using a popup-based OAuth authentication flow.
951963

952964
If succeeds, returns the signed in user along with the provider's credential. If sign in was unsuccessful, returns an error object containing additional information about the error.
953965

954-
This method does not work in a Node.js environment.
966+
This method does not work in a Node.js environment or with [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
955967

956968
<b>Signature:</b>
957969

@@ -993,7 +1005,7 @@ Authenticates a Firebase client using a full-page redirect flow.
9931005

9941006
To handle the results and errors for this operation, refer to [getRedirectResult()](./auth.md#getredirectresult_c35dc1f)<!-- -->. Follow the [best practices](https://firebase.google.com/docs/auth/web/redirect-best-practices) when using [signInWithRedirect()](./auth.md#signinwithredirect_770f816)<!-- -->.
9951007

996-
This method does not work in a Node.js environment.
1008+
This method does not work in a Node.js environment or with [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
9971009

9981010
<b>Signature:</b>
9991011

@@ -1045,6 +1057,8 @@ const operationType = result.operationType;
10451057

10461058
Signs out the current user.
10471059

1060+
This method is not supported by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
1061+
10481062
<b>Signature:</b>
10491063

10501064
```typescript
@@ -1071,6 +1085,8 @@ This will trigger [onAuthStateChanged()](./auth.md#onauthstatechanged_b0d07ab) a
10711085

10721086
The operation fails with an error if the user to be updated belongs to a different Firebase project.
10731087

1088+
This method is not supported by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
1089+
10741090
<b>Signature:</b>
10751091

10761092
```typescript
@@ -1347,7 +1363,7 @@ Links the [OAuthProvider](./auth.oauthprovider.md#oauthprovider_class) to the us
13471363

13481364
To handle the results and errors for this operation, refer to [getRedirectResult()](./auth.md#getredirectresult_c35dc1f)<!-- -->. Follow the [best practices](https://firebase.google.com/docs/auth/web/redirect-best-practices) when using [linkWithRedirect()](./auth.md#linkwithredirect_41c0b31)<!-- -->.
13491365

1350-
This method does not work in a Node.js environment.
1366+
This method does not work in a Node.js environment or with [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
13511367

13521368
<b>Signature:</b>
13531369

@@ -1411,6 +1427,8 @@ Re-authenticates a user using a fresh credential.
14111427

14121428
Use before operations such as [updatePassword()](./auth.md#updatepassword_6df673e) that require tokens from recent sign-in attempts. This method can be used to recover from a `CREDENTIAL_TOO_OLD_LOGIN_AGAIN` error or a `TOKEN_EXPIRED` error.
14131429

1430+
This method is not supported on any [User](./auth.user.md#user_interface) signed in by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
1431+
14141432
<b>Signature:</b>
14151433

14161434
```typescript
@@ -1434,7 +1452,7 @@ Re-authenticates a user using a fresh phone credential.
14341452

14351453
Use before operations such as [updatePassword()](./auth.md#updatepassword_6df673e) that require tokens from recent sign-in attempts.
14361454

1437-
This method does not work in a Node.js environment.
1455+
This method does not work in a Node.js environment or on any [User](./auth.user.md#user_interface) signed in by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
14381456

14391457
<b>Signature:</b>
14401458

@@ -1460,7 +1478,7 @@ Reauthenticates the current user with the specified [OAuthProvider](./auth.oauth
14601478

14611479
If the reauthentication is successful, the returned result will contain the user and the provider's credential.
14621480

1463-
This method does not work in a Node.js environment.
1481+
This method does not work in a Node.js environment or on any [User](./auth.user.md#user_interface) signed in by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
14641482

14651483
<b>Signature:</b>
14661484

@@ -1498,7 +1516,7 @@ Reauthenticates the current user with the specified [OAuthProvider](./auth.oauth
14981516

14991517
To handle the results and errors for this operation, refer to [getRedirectResult()](./auth.md#getredirectresult_c35dc1f)<!-- -->. Follow the [best practices](https://firebase.google.com/docs/auth/web/redirect-best-practices) when using [reauthenticateWithRedirect()](./auth.md#reauthenticatewithredirect_41c0b31)<!-- -->.
15001518

1501-
This method does not work in a Node.js environment.
1519+
This method does not work in a Node.js environment or with [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
15021520

15031521
<b>Signature:</b>
15041522

@@ -1630,6 +1648,8 @@ Updates the user's email address.
16301648

16311649
An email will be sent to the original email address (if it was set) that allows to revoke the email address change, in order to protect them from account hijacking.
16321650

1651+
This method is not supported on any [User](./auth.user.md#user_interface) signed in by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
1652+
16331653
Important: this is a security sensitive operation that requires the user to have recently signed in. If this requirement isn't met, ask the user to authenticate again and then call [reauthenticateWithCredential()](./auth.md#reauthenticatewithcredential_60f8043)<!-- -->.
16341654

16351655
<b>Signature:</b>
@@ -1676,7 +1696,7 @@ Promise&lt;void&gt;
16761696

16771697
Updates the user's phone number.
16781698

1679-
This method does not work in a Node.js environment.
1699+
This method does not work in a Node.js environment or on any [User](./auth.user.md#user_interface) signed in by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
16801700

16811701
<b>Signature:</b>
16821702

docs-devsite/auth.user.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ Deletes and signs out the user.
121121
122122
Important: this is a security-sensitive operation that requires the user to have recently signed in. If this requirement isn't met, ask the user to authenticate again and then call one of the reauthentication methods like [reauthenticateWithCredential()](./auth.md#reauthenticatewithcredential_60f8043)<!-- -->.
123123
124+
This method is not supported on any [User](./auth.user.md#user_interface) signed in by [Auth](./auth.auth.md#auth_interface) instances created with a [FirebaseServerApp](./app.firebaseserverapp.md#firebaseserverapp_interface)<!-- -->.
125+
124126
<b>Signature:</b>
125127
126128
```typescript

packages/auth/src/core/auth/auth_impl.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ import {
6262
PersistenceUserManager
6363
} from '../persistence/persistence_user_manager';
6464
import { _reloadWithoutSaving } from '../user/reload';
65-
import { _assert } from '../util/assert';
65+
import { _assert, _createError } from '../util/assert';
6666
import { _getInstance } from '../util/instantiator';
6767
import { _getUserLanguage } from '../util/navigator';
6868
import { _getClientVersion } from '../util/version';
@@ -354,6 +354,11 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
354354
}
355355

356356
async updateCurrentUser(userExtern: User | null): Promise<void> {
357+
if (_isFirebaseServerApp(this.app)) {
358+
return Promise.reject(
359+
_createError(this, AuthErrorCode.OPERATION_NOT_SUPPORTED)
360+
);
361+
}
357362
// The public updateCurrentUser method needs to make a copy of the user,
358363
// and also check that the project matches
359364
const user = userExtern
@@ -395,6 +400,11 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
395400
}
396401

397402
async signOut(): Promise<void> {
403+
if (_isFirebaseServerApp(this.app)) {
404+
return Promise.reject(
405+
_createError(this, AuthErrorCode.OPERATION_NOT_SUPPORTED)
406+
);
407+
}
398408
// Run first, to block _setRedirectUser() if any callbacks fail.
399409
await this.beforeStateQueue.runMiddleware(null);
400410
// Clear the redirect user when signOut is called
@@ -408,6 +418,11 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
408418
}
409419

410420
setPersistence(persistence: Persistence): Promise<void> {
421+
if (_isFirebaseServerApp(this.app)) {
422+
return Promise.reject(
423+
_createError(this, AuthErrorCode.OPERATION_NOT_SUPPORTED)
424+
);
425+
}
411426
return this.queue(async () => {
412427
await this.assertedPersistence.setPersistence(_getInstance(persistence));
413428
});

packages/auth/src/core/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ export {
4646
* remembered or not. It also makes it easier to never persist the `Auth` state for applications
4747
* that are shared by other users or have sensitive data.
4848
*
49-
* This method does not work in a Node.js environment.
49+
* This method does not work in a Node.js environment or with {@link Auth} instances created with a
50+
* {@link @firebase/app#FirebaseServerApp}.
5051
*
5152
* @example
5253
* ```javascript
@@ -223,6 +224,9 @@ export function useDeviceLanguage(auth: Auth): void {
223224
* The operation fails with an error if the user to be updated belongs to a different Firebase
224225
* project.
225226
*
227+
* This method is not supported by {@link Auth} instances created with a
228+
* {@link @firebase/app#FirebaseServerApp}.
229+
*
226230
* @param auth - The {@link Auth} instance.
227231
* @param user - The new {@link User}.
228232
*
@@ -237,6 +241,10 @@ export function updateCurrentUser(
237241
/**
238242
* Signs out the current user.
239243
*
244+
* @remarks
245+
* This method is not supported by {@link Auth} instances created with a
246+
* {@link @firebase/app#FirebaseServerApp}.
247+
*
240248
* @param auth - The {@link Auth} instance.
241249
*
242250
* @public

packages/auth/src/core/strategies/anonymous.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import { UserInternal } from '../../model/user';
2121
import { UserCredentialImpl } from '../user/user_credential_impl';
2222
import { _castAuth } from '../auth/auth_impl';
2323
import { OperationType } from '../../model/enums';
24+
import { _isFirebaseServerApp } from '@firebase/app';
25+
import { _createError } from '../../core/util/assert';
26+
import { AuthErrorCode } from '../../core/errors';
2427

2528
/**
2629
* Asynchronously signs in as an anonymous user.
@@ -29,11 +32,19 @@ import { OperationType } from '../../model/enums';
2932
* If there is already an anonymous user signed in, that user will be returned; otherwise, a
3033
* new anonymous user identity will be created and returned.
3134
*
35+
* This method is not supported by {@link Auth} instances created with a
36+
* {@link @firebase/app#FirebaseServerApp}.
37+
*
3238
* @param auth - The {@link Auth} instance.
3339
*
3440
* @public
3541
*/
3642
export async function signInAnonymously(auth: Auth): Promise<UserCredential> {
43+
if (_isFirebaseServerApp(auth.app)) {
44+
return Promise.reject(
45+
_createError(auth, AuthErrorCode.OPERATION_NOT_SUPPORTED)
46+
);
47+
}
3748
const authInternal = _castAuth(auth);
3849
await authInternal._initializationPromise;
3950
if (authInternal.currentUser?.isAnonymous) {

packages/auth/src/core/strategies/credential.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,20 @@ import { UserCredentialImpl } from '../user/user_credential_impl';
2727
import { _castAuth } from '../auth/auth_impl';
2828
import { getModularInstance } from '@firebase/util';
2929
import { OperationType } from '../../model/enums';
30+
import { _isFirebaseServerApp } from '@firebase/app';
31+
import { _createError } from '../../core/util/assert';
32+
import { AuthErrorCode } from '../../core/errors';
3033

3134
export async function _signInWithCredential(
3235
auth: AuthInternal,
3336
credential: AuthCredential,
3437
bypassAuthState = false
3538
): Promise<UserCredential> {
39+
if (_isFirebaseServerApp(auth.app)) {
40+
return Promise.reject(
41+
_createError(auth, AuthErrorCode.OPERATION_NOT_SUPPORTED)
42+
);
43+
}
3644
const operationType = OperationType.SIGN_IN;
3745
const response = await _processCredentialSavingMfaContextIfNecessary(
3846
auth,
@@ -57,6 +65,9 @@ export async function _signInWithCredential(
5765
* @remarks
5866
* An {@link AuthProvider} can be used to generate the credential.
5967
*
68+
* This method is not supported by {@link Auth} instances created with a
69+
* {@link @firebase/app#FirebaseServerApp}.
70+
*
6071
* @param auth - The {@link Auth} instance.
6172
* @param credential - The auth credential.
6273
*
@@ -99,6 +110,9 @@ export async function linkWithCredential(
99110
* attempts. This method can be used to recover from a `CREDENTIAL_TOO_OLD_LOGIN_AGAIN` error
100111
* or a `TOKEN_EXPIRED` error.
101112
*
113+
* This method is not supported on any {@link User} signed in by {@link Auth} instances
114+
* created with a {@link @firebase/app#FirebaseServerApp}.
115+
*
102116
* @param user - The user.
103117
* @param credential - The auth credential.
104118
*

packages/auth/src/core/strategies/custom_token.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import { IdTokenResponse } from '../../model/id_token';
2222
import { UserCredentialImpl } from '../user/user_credential_impl';
2323
import { _castAuth } from '../auth/auth_impl';
2424
import { OperationType } from '../../model/enums';
25-
25+
import { _isFirebaseServerApp } from '@firebase/app';
26+
import { _createError } from '../../core/util/assert';
27+
import { AuthErrorCode } from '../../core/errors';
2628
/**
2729
* Asynchronously signs in using a custom token.
2830
*
@@ -34,6 +36,9 @@ import { OperationType } from '../../model/enums';
3436
*
3537
* Fails with an error if the token is invalid, expired, or not accepted by the Firebase Auth service.
3638
*
39+
* This method is not supported by {@link Auth} instances created with a
40+
* {@link @firebase/app#FirebaseServerApp}.
41+
*
3742
* @param auth - The {@link Auth} instance.
3843
* @param customToken - The custom token to sign in with.
3944
*
@@ -43,6 +48,11 @@ export async function signInWithCustomToken(
4348
auth: Auth,
4449
customToken: string
4550
): Promise<UserCredential> {
51+
if (_isFirebaseServerApp(auth.app)) {
52+
return Promise.reject(
53+
_createError(auth, AuthErrorCode.OPERATION_NOT_SUPPORTED)
54+
);
55+
}
4656
const authInternal = _castAuth(auth);
4757
const response: IdTokenResponse = await getIdTokenResponse(authInternal, {
4858
token: customToken,

0 commit comments

Comments
 (0)