@firebase/auth 0.19.12 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/auth-public.d.ts +30 -0
  3. package/dist/auth.d.ts +38 -1
  4. package/dist/cordova/index.js +2 -2
  5. package/dist/cordova/internal/index.d.ts +1 -0
  6. package/dist/cordova/internal.js +3 -2
  7. package/dist/cordova/internal.js.map +1 -1
  8. package/dist/cordova/{popup_redirect-fd81f644.js → popup_redirect-1228b67a.js} +203 -43
  9. package/dist/cordova/popup_redirect-1228b67a.js.map +1 -0
  10. package/dist/cordova/src/core/auth/auth_impl.d.ts +3 -1
  11. package/dist/cordova/src/core/auth/middleware.d.ts +25 -0
  12. package/dist/cordova/src/core/auth/middleware.test.d.ts +17 -0
  13. package/dist/cordova/src/core/errors.d.ts +7 -1
  14. package/dist/cordova/src/core/index.d.ts +11 -0
  15. package/dist/cordova/src/core/strategies/redirect.d.ts +1 -0
  16. package/dist/cordova/src/model/popup_redirect.d.ts +2 -0
  17. package/dist/cordova/src/model/public_types.d.ts +10 -0
  18. package/dist/cordova/test/integration/flows/middleware_test_generator.d.ts +18 -0
  19. package/dist/cordova/test/integration/webdriver/util/functions.d.ts +4 -0
  20. package/dist/esm2017/{index-7078a255.js → index-815f1b87.js} +143 -18
  21. package/dist/esm2017/index-815f1b87.js.map +1 -0
  22. package/dist/esm2017/index.js +1 -1
  23. package/dist/esm2017/internal/index.d.ts +1 -0
  24. package/dist/esm2017/internal.js +3 -2
  25. package/dist/esm2017/internal.js.map +1 -1
  26. package/dist/esm2017/src/core/auth/auth_impl.d.ts +3 -1
  27. package/dist/esm2017/src/core/auth/middleware.d.ts +25 -0
  28. package/dist/esm2017/src/core/auth/middleware.test.d.ts +17 -0
  29. package/dist/esm2017/src/core/errors.d.ts +7 -1
  30. package/dist/esm2017/src/core/index.d.ts +11 -0
  31. package/dist/esm2017/src/core/strategies/redirect.d.ts +1 -0
  32. package/dist/esm2017/src/model/popup_redirect.d.ts +2 -0
  33. package/dist/esm2017/src/model/public_types.d.ts +10 -0
  34. package/dist/esm2017/test/integration/flows/middleware_test_generator.d.ts +18 -0
  35. package/dist/esm2017/test/integration/webdriver/util/functions.d.ts +4 -0
  36. package/dist/esm5/{index-7a476dcd.js → index-dc27d95e.js} +203 -43
  37. package/dist/esm5/index-dc27d95e.js.map +1 -0
  38. package/dist/esm5/index.js +1 -1
  39. package/dist/esm5/internal/index.d.ts +1 -0
  40. package/dist/esm5/internal.js +3 -2
  41. package/dist/esm5/internal.js.map +1 -1
  42. package/dist/esm5/src/core/auth/auth_impl.d.ts +3 -1
  43. package/dist/esm5/src/core/auth/middleware.d.ts +25 -0
  44. package/dist/esm5/src/core/auth/middleware.test.d.ts +17 -0
  45. package/dist/esm5/src/core/errors.d.ts +7 -1
  46. package/dist/esm5/src/core/index.d.ts +11 -0
  47. package/dist/esm5/src/core/strategies/redirect.d.ts +1 -0
  48. package/dist/esm5/src/model/popup_redirect.d.ts +2 -0
  49. package/dist/esm5/src/model/public_types.d.ts +10 -0
  50. package/dist/esm5/test/integration/flows/middleware_test_generator.d.ts +18 -0
  51. package/dist/esm5/test/integration/webdriver/util/functions.d.ts +4 -0
  52. package/dist/index.webworker.esm5.js +198 -42
  53. package/dist/index.webworker.esm5.js.map +1 -1
  54. package/dist/internal/index.d.ts +1 -0
  55. package/dist/node/{index-eabd3e6c.js → index-ec34877a.js} +199 -42
  56. package/dist/node/index-ec34877a.js.map +1 -0
  57. package/dist/node/index.js +2 -1
  58. package/dist/node/index.js.map +1 -1
  59. package/dist/node/internal/index.d.ts +1 -0
  60. package/dist/node/internal.js +7 -1
  61. package/dist/node/internal.js.map +1 -1
  62. package/dist/node/src/core/auth/auth_impl.d.ts +3 -1
  63. package/dist/node/src/core/auth/middleware.d.ts +25 -0
  64. package/dist/node/src/core/auth/middleware.test.d.ts +17 -0
  65. package/dist/node/src/core/errors.d.ts +7 -1
  66. package/dist/node/src/core/index.d.ts +11 -0
  67. package/dist/node/src/core/strategies/redirect.d.ts +1 -0
  68. package/dist/node/src/model/popup_redirect.d.ts +2 -0
  69. package/dist/node/src/model/public_types.d.ts +10 -0
  70. package/dist/node/test/integration/flows/middleware_test_generator.d.ts +18 -0
  71. package/dist/node/test/integration/webdriver/util/functions.d.ts +4 -0
  72. package/dist/node-esm/{index-d709908a.js → index-c85cf380.js} +139 -18
  73. package/dist/node-esm/index-c85cf380.js.map +1 -0
  74. package/dist/node-esm/index.js +1 -1
  75. package/dist/node-esm/internal/index.d.ts +1 -0
  76. package/dist/node-esm/internal.js +7 -3
  77. package/dist/node-esm/internal.js.map +1 -1
  78. package/dist/node-esm/src/core/auth/auth_impl.d.ts +3 -1
  79. package/dist/node-esm/src/core/auth/middleware.d.ts +25 -0
  80. package/dist/node-esm/src/core/auth/middleware.test.d.ts +17 -0
  81. package/dist/node-esm/src/core/errors.d.ts +7 -1
  82. package/dist/node-esm/src/core/index.d.ts +11 -0
  83. package/dist/node-esm/src/core/strategies/redirect.d.ts +1 -0
  84. package/dist/node-esm/src/model/popup_redirect.d.ts +2 -0
  85. package/dist/node-esm/src/model/public_types.d.ts +10 -0
  86. package/dist/node-esm/test/integration/flows/middleware_test_generator.d.ts +18 -0
  87. package/dist/node-esm/test/integration/webdriver/util/functions.d.ts +4 -0
  88. package/dist/rn/index.js +2 -1
  89. package/dist/rn/index.js.map +1 -1
  90. package/dist/rn/internal/index.d.ts +1 -0
  91. package/dist/rn/internal.js +8 -1
  92. package/dist/rn/internal.js.map +1 -1
  93. package/dist/rn/{phone-eec7f987.js → phone-ae029e3c.js} +199 -42
  94. package/dist/rn/phone-ae029e3c.js.map +1 -0
  95. package/dist/rn/src/core/auth/auth_impl.d.ts +3 -1
  96. package/dist/rn/src/core/auth/middleware.d.ts +25 -0
  97. package/dist/rn/src/core/auth/middleware.test.d.ts +17 -0
  98. package/dist/rn/src/core/errors.d.ts +7 -1
  99. package/dist/rn/src/core/index.d.ts +11 -0
  100. package/dist/rn/src/core/strategies/redirect.d.ts +1 -0
  101. package/dist/rn/src/model/popup_redirect.d.ts +2 -0
  102. package/dist/rn/src/model/public_types.d.ts +10 -0
  103. package/dist/rn/test/integration/flows/middleware_test_generator.d.ts +18 -0
  104. package/dist/rn/test/integration/webdriver/util/functions.d.ts +4 -0
  105. package/dist/src/core/auth/auth_impl.d.ts +3 -1
  106. package/dist/src/core/auth/middleware.d.ts +25 -0
  107. package/dist/src/core/auth/middleware.test.d.ts +17 -0
  108. package/dist/src/core/errors.d.ts +7 -1
  109. package/dist/src/core/index.d.ts +11 -0
  110. package/dist/src/core/strategies/redirect.d.ts +1 -0
  111. package/dist/src/model/popup_redirect.d.ts +2 -0
  112. package/dist/src/model/public_types.d.ts +10 -0
  113. package/dist/test/integration/flows/middleware_test_generator.d.ts +18 -0
  114. package/dist/test/integration/webdriver/util/functions.d.ts +4 -0
  115. package/package.json +6 -6
  116. package/dist/cordova/popup_redirect-fd81f644.js.map +0 -1
  117. package/dist/esm2017/index-7078a255.js.map +0 -1
  118. package/dist/esm5/index-7a476dcd.js.map +0 -1
  119. package/dist/node/index-eabd3e6c.js.map +0 -1
  120. package/dist/node-esm/index-d709908a.js.map +0 -1
  121. package/dist/rn/phone-eec7f987.js.map +0 -1
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { AuthInternal } from '../../model/auth';
18
+ import { Unsubscribe, User } from '../../model/public_types';
19
+ export declare class AuthMiddlewareQueue {
20
+ private readonly auth;
21
+ private readonly queue;
22
+ constructor(auth: AuthInternal);
23
+ pushCallback(callback: (user: User | null) => void | Promise<void>, onAbort?: () => void): Unsubscribe;
24
+ runMiddleware(nextUser: User | null): Promise<void>;
25
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ export {};
@@ -72,6 +72,7 @@ export declare const enum AuthErrorCode {
72
72
  INVALID_SENDER = "invalid-sender",
73
73
  INVALID_SESSION_INFO = "invalid-verification-id",
74
74
  INVALID_TENANT_ID = "invalid-tenant-id",
75
+ LOGIN_BLOCKED = "login-blocked",
75
76
  MFA_INFO_NOT_FOUND = "multi-factor-info-not-found",
76
77
  MFA_REQUIRED = "multi-factor-auth-required",
77
78
  MISSING_ANDROID_PACKAGE_NAME = "missing-android-pkg-name",
@@ -154,9 +155,10 @@ export interface NamedErrorParams {
154
155
  */
155
156
  declare type GenericAuthErrorParams = {
156
157
  [key in Exclude<AuthErrorCode, AuthErrorCode.ARGUMENT_ERROR | AuthErrorCode.DEPENDENT_SDK_INIT_BEFORE_AUTH | AuthErrorCode.INTERNAL_ERROR | AuthErrorCode.MFA_REQUIRED | AuthErrorCode.NO_AUTH_EVENT | AuthErrorCode.OPERATION_NOT_SUPPORTED>]: {
157
- appName: AppName;
158
+ appName?: AppName;
158
159
  email?: string;
159
160
  phoneNumber?: string;
161
+ message?: string;
160
162
  };
161
163
  };
162
164
  /**
@@ -172,6 +174,10 @@ export interface AuthErrorParams extends GenericAuthErrorParams {
172
174
  [AuthErrorCode.INTERNAL_ERROR]: {
173
175
  appName?: AppName;
174
176
  };
177
+ [AuthErrorCode.LOGIN_BLOCKED]: {
178
+ appName?: AppName;
179
+ originalMessage?: string;
180
+ };
175
181
  [AuthErrorCode.OPERATION_NOT_SUPPORTED]: {
176
182
  appName?: AppName;
177
183
  };
@@ -50,6 +50,17 @@ export declare function setPersistence(auth: Auth, persistence: Persistence): Pr
50
50
  * @public
51
51
  */
52
52
  export declare function onIdTokenChanged(auth: Auth, nextOrObserver: NextOrObserver<User>, error?: ErrorFn, completed?: CompleteFn): Unsubscribe;
53
+ /**
54
+ * Adds a blocking callback that runs before an auth state change
55
+ * sets a new user.
56
+ *
57
+ * @param auth - The {@link Auth} instance.
58
+ * @param callback - callback triggered before new user value is set.
59
+ * If this throws, it blocks the user from being set.
60
+ * @param onAbort - callback triggered if a later `beforeAuthStateChanged()`
61
+ * callback throws, allowing you to undo any side effects.
62
+ */
63
+ export declare function beforeAuthStateChanged(auth: Auth, callback: (user: User | null) => void | Promise<void>, onAbort?: () => void): Unsubscribe;
53
64
  /**
54
65
  * Adds an observer for changes to the user's sign-in state.
55
66
  *
@@ -33,3 +33,4 @@ export declare class RedirectAction extends AbstractPopupRedirectOperation {
33
33
  export declare function _getAndClearPendingRedirectStatus(resolver: PopupRedirectResolverInternal, auth: AuthInternal): Promise<boolean>;
34
34
  export declare function _setPendingRedirectStatus(resolver: PopupRedirectResolverInternal, auth: AuthInternal): Promise<void>;
35
35
  export declare function _clearRedirectOutcomes(): void;
36
+ export declare function _overrideRedirectResult(auth: AuthInternal, result: () => Promise<UserCredentialInternal | null>): void;
@@ -18,6 +18,7 @@ import { Auth, AuthProvider, Persistence, PopupRedirectResolver, UserCredential
18
18
  import { FirebaseError } from '@firebase/util';
19
19
  import { AuthPopup } from '../platform_browser/util/popup';
20
20
  import { AuthInternal } from './auth';
21
+ import { UserCredentialInternal } from './user';
21
22
  export declare const enum EventFilter {
22
23
  POPUP = 0,
23
24
  REDIRECT = 1
@@ -89,4 +90,5 @@ export interface PopupRedirectResolverInternal extends PopupRedirectResolver {
89
90
  _redirectPersistence: Persistence;
90
91
  _originValidation(auth: Auth): Promise<void>;
91
92
  _completeRedirectFn: (auth: Auth, resolver: PopupRedirectResolver, bypassAuthState: boolean) => Promise<UserCredential | null>;
93
+ _overrideRedirectResult: (auth: AuthInternal, resultGetter: () => Promise<UserCredentialInternal | null>) => void;
92
94
  }
@@ -228,6 +228,16 @@ export interface Auth {
228
228
  * @param completed - callback triggered when observer is removed.
229
229
  */
230
230
  onAuthStateChanged(nextOrObserver: NextOrObserver<User | null>, error?: ErrorFn, completed?: CompleteFn): Unsubscribe;
231
+ /**
232
+ * Adds a blocking callback that runs before an auth state change
233
+ * sets a new user.
234
+ *
235
+ * @param callback - callback triggered before new user value is set.
236
+ * If this throws, it blocks the user from being set.
237
+ * @param onAbort - callback triggered if a later `beforeAuthStateChanged()`
238
+ * callback throws, allowing you to undo any side effects.
239
+ */
240
+ beforeAuthStateChanged(callback: (user: User | null) => void | Promise<void>, onAbort?: () => void): Unsubscribe;
231
241
  /**
232
242
  * Adds an observer for changes to the signed-in user's ID token.
233
243
  *
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { Auth } from '@firebase/auth';
18
+ export declare function generateMiddlewareTests(authGetter: () => Auth, signIn: () => Promise<unknown>): void;
@@ -70,6 +70,10 @@ export declare enum PersistenceFunction {
70
70
  SET_PERSISTENCE_INDEXED_DB = "persistence.setPersistenceIndexedDB",
71
71
  SET_PERSISTENCE_LOCAL_STORAGE = "persistence.setPersistenceLocalStorage"
72
72
  }
73
+ export declare enum MiddlewareFunction {
74
+ ATTACH_BLOCKING_MIDDLEWARE = "middleware.attachBlockingMiddleware",
75
+ ATTACH_BLOCKING_MIDDLEWARE_ON_START = "middleware.attachBlockingMiddlewareOnStart"
76
+ }
73
77
  /** Available firebase UI functions (only for compat tests) */
74
78
  export declare enum UiFunction {
75
79
  LOAD = "ui.loadUiCode",
@@ -199,6 +199,7 @@ function _debugErrorMap() {
199
199
  'Please fix by going to the Auth email templates section in the Firebase Console.',
200
200
  ["invalid-verification-id" /* INVALID_SESSION_INFO */]: 'The verification ID used to create the phone auth credential is invalid.',
201
201
  ["invalid-tenant-id" /* INVALID_TENANT_ID */]: "The Auth instance's tenant ID is invalid.",
202
+ ["login-blocked" /* LOGIN_BLOCKED */]: "Login blocked by user-provided method: {$originalMessage}",
202
203
  ["missing-android-pkg-name" /* MISSING_ANDROID_PACKAGE_NAME */]: 'An Android Package Name must be provided if the Android App is required to be installed.',
203
204
  ["auth-domain-config-required" /* MISSING_AUTH_DOMAIN */]: 'Be sure to include authDomain when calling firebase.initializeApp(), ' +
204
205
  'by following the instructions in the Firebase console.',
@@ -2103,6 +2104,83 @@ function _getClientVersion(clientPlatform, frameworks = []) {
2103
2104
  return `${reportedPlatform}/${"JsCore" /* CORE */}/${SDK_VERSION}/${reportedFrameworks}`;
2104
2105
  }
2105
2106
 
2107
+ /**
2108
+ * @license
2109
+ * Copyright 2022 Google LLC
2110
+ *
2111
+ * Licensed under the Apache License, Version 2.0 (the "License");
2112
+ * you may not use this file except in compliance with the License.
2113
+ * You may obtain a copy of the License at
2114
+ *
2115
+ * http://www.apache.org/licenses/LICENSE-2.0
2116
+ *
2117
+ * Unless required by applicable law or agreed to in writing, software
2118
+ * distributed under the License is distributed on an "AS IS" BASIS,
2119
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2120
+ * See the License for the specific language governing permissions and
2121
+ * limitations under the License.
2122
+ */
2123
+ class AuthMiddlewareQueue {
2124
+ constructor(auth) {
2125
+ this.auth = auth;
2126
+ this.queue = [];
2127
+ }
2128
+ pushCallback(callback, onAbort) {
2129
+ // The callback could be sync or async. Wrap it into a
2130
+ // function that is always async.
2131
+ const wrappedCallback = (user) => new Promise((resolve, reject) => {
2132
+ try {
2133
+ const result = callback(user);
2134
+ // Either resolve with existing promise or wrap a non-promise
2135
+ // return value into a promise.
2136
+ resolve(result);
2137
+ }
2138
+ catch (e) {
2139
+ // Sync callback throws.
2140
+ reject(e);
2141
+ }
2142
+ });
2143
+ // Attach the onAbort if present
2144
+ wrappedCallback.onAbort = onAbort;
2145
+ this.queue.push(wrappedCallback);
2146
+ const index = this.queue.length - 1;
2147
+ return () => {
2148
+ // Unsubscribe. Replace with no-op. Do not remove from array, or it will disturb
2149
+ // indexing of other elements.
2150
+ this.queue[index] = () => Promise.resolve();
2151
+ };
2152
+ }
2153
+ async runMiddleware(nextUser) {
2154
+ if (this.auth.currentUser === nextUser) {
2155
+ return;
2156
+ }
2157
+ // While running the middleware, build a temporary stack of onAbort
2158
+ // callbacks to call if one middleware callback rejects.
2159
+ const onAbortStack = [];
2160
+ try {
2161
+ for (const beforeStateCallback of this.queue) {
2162
+ await beforeStateCallback(nextUser);
2163
+ // Only push the onAbort if the callback succeeds
2164
+ if (beforeStateCallback.onAbort) {
2165
+ onAbortStack.push(beforeStateCallback.onAbort);
2166
+ }
2167
+ }
2168
+ }
2169
+ catch (e) {
2170
+ // Run all onAbort, with separate try/catch to ignore any errors and
2171
+ // continue
2172
+ onAbortStack.reverse();
2173
+ for (const onAbort of onAbortStack) {
2174
+ try {
2175
+ onAbort();
2176
+ }
2177
+ catch (_) { /* swallow error */ }
2178
+ }
2179
+ throw this.auth._errorFactory.create("login-blocked" /* LOGIN_BLOCKED */, { originalMessage: e.message });
2180
+ }
2181
+ }
2182
+ }
2183
+
2106
2184
  /**
2107
2185
  * @license
2108
2186
  * Copyright 2020 Google LLC
@@ -2129,6 +2207,7 @@ class AuthImpl {
2129
2207
  this.operations = Promise.resolve();
2130
2208
  this.authStateSubscription = new Subscription(this);
2131
2209
  this.idTokenSubscription = new Subscription(this);
2210
+ this.beforeStateQueue = new AuthMiddlewareQueue(this);
2132
2211
  this.redirectUser = null;
2133
2212
  this.isProactiveRefreshEnabled = false;
2134
2213
  // Any network calls will set this to true and prevent subsequent emulator
@@ -2205,16 +2284,19 @@ class AuthImpl {
2205
2284
  return;
2206
2285
  }
2207
2286
  // Update current Auth state. Either a new login or logout.
2208
- await this._updateCurrentUser(user);
2287
+ // Skip blocking callbacks, they should not apply to a change in another tab.
2288
+ await this._updateCurrentUser(user, /* skipBeforeStateCallbacks */ true);
2209
2289
  }
2210
2290
  async initializeCurrentUser(popupRedirectResolver) {
2211
2291
  var _a;
2212
2292
  // First check to see if we have a pending redirect event.
2213
- let storedUser = (await this.assertedPersistence.getCurrentUser());
2293
+ const previouslyStoredUser = (await this.assertedPersistence.getCurrentUser());
2294
+ let futureCurrentUser = previouslyStoredUser;
2295
+ let needsTocheckMiddleware = false;
2214
2296
  if (popupRedirectResolver && this.config.authDomain) {
2215
2297
  await this.getOrInitRedirectPersistenceManager();
2216
2298
  const redirectUserEventId = (_a = this.redirectUser) === null || _a === void 0 ? void 0 : _a._redirectEventId;
2217
- const storedUserEventId = storedUser === null || storedUser === void 0 ? void 0 : storedUser._redirectEventId;
2299
+ const storedUserEventId = futureCurrentUser === null || futureCurrentUser === void 0 ? void 0 : futureCurrentUser._redirectEventId;
2218
2300
  const result = await this.tryRedirectSignIn(popupRedirectResolver);
2219
2301
  // If the stored user (i.e. the old "currentUser") has a redirectId that
2220
2302
  // matches the redirect user, then we want to initially sign in with the
@@ -2222,18 +2304,34 @@ class AuthImpl {
2222
2304
  // TODO(samgho): More thoroughly test all of this
2223
2305
  if ((!redirectUserEventId || redirectUserEventId === storedUserEventId) &&
2224
2306
  (result === null || result === void 0 ? void 0 : result.user)) {
2225
- storedUser = result.user;
2307
+ futureCurrentUser = result.user;
2308
+ needsTocheckMiddleware = true;
2226
2309
  }
2227
2310
  }
2228
2311
  // If no user in persistence, there is no current user. Set to null.
2229
- if (!storedUser) {
2312
+ if (!futureCurrentUser) {
2230
2313
  return this.directlySetCurrentUser(null);
2231
2314
  }
2232
- if (!storedUser._redirectEventId) {
2233
- // This isn't a redirect user, we can reload and bail
2234
- // This will also catch the redirected user, if available, as that method
2235
- // strips the _redirectEventId
2236
- return this.reloadAndSetCurrentUserOrClear(storedUser);
2315
+ if (!futureCurrentUser._redirectEventId) {
2316
+ // This isn't a redirect link operation, we can reload and bail.
2317
+ // First though, ensure that we check the middleware is happy.
2318
+ if (needsTocheckMiddleware) {
2319
+ try {
2320
+ await this.beforeStateQueue.runMiddleware(futureCurrentUser);
2321
+ }
2322
+ catch (e) {
2323
+ futureCurrentUser = previouslyStoredUser;
2324
+ // We know this is available since the bit is only set when the
2325
+ // resolver is available
2326
+ this._popupRedirectResolver._overrideRedirectResult(this, () => Promise.reject(e));
2327
+ }
2328
+ }
2329
+ if (futureCurrentUser) {
2330
+ return this.reloadAndSetCurrentUserOrClear(futureCurrentUser);
2331
+ }
2332
+ else {
2333
+ return this.directlySetCurrentUser(null);
2334
+ }
2237
2335
  }
2238
2336
  _assert(this._popupRedirectResolver, this, "argument-error" /* ARGUMENT_ERROR */);
2239
2337
  await this.getOrInitRedirectPersistenceManager();
@@ -2241,10 +2339,10 @@ class AuthImpl {
2241
2339
  // DO NOT reload the current user, otherwise they'll be cleared from storage.
2242
2340
  // This is important for the reauthenticateWithRedirect() flow.
2243
2341
  if (this.redirectUser &&
2244
- this.redirectUser._redirectEventId === storedUser._redirectEventId) {
2245
- return this.directlySetCurrentUser(storedUser);
2342
+ this.redirectUser._redirectEventId === futureCurrentUser._redirectEventId) {
2343
+ return this.directlySetCurrentUser(futureCurrentUser);
2246
2344
  }
2247
- return this.reloadAndSetCurrentUserOrClear(storedUser);
2345
+ return this.reloadAndSetCurrentUserOrClear(futureCurrentUser);
2248
2346
  }
2249
2347
  async tryRedirectSignIn(redirectResolver) {
2250
2348
  // The redirect user needs to be checked (and signed in if available)
@@ -2305,24 +2403,31 @@ class AuthImpl {
2305
2403
  }
2306
2404
  return this._updateCurrentUser(user && user._clone(this));
2307
2405
  }
2308
- async _updateCurrentUser(user) {
2406
+ async _updateCurrentUser(user, skipBeforeStateCallbacks = false) {
2309
2407
  if (this._deleted) {
2310
2408
  return;
2311
2409
  }
2312
2410
  if (user) {
2313
2411
  _assert(this.tenantId === user.tenantId, this, "tenant-id-mismatch" /* TENANT_ID_MISMATCH */);
2314
2412
  }
2413
+ if (!skipBeforeStateCallbacks) {
2414
+ await this.beforeStateQueue.runMiddleware(user);
2415
+ }
2315
2416
  return this.queue(async () => {
2316
2417
  await this.directlySetCurrentUser(user);
2317
2418
  this.notifyAuthListeners();
2318
2419
  });
2319
2420
  }
2320
2421
  async signOut() {
2422
+ // Run first, to block _setRedirectUser() if any callbacks fail.
2423
+ await this.beforeStateQueue.runMiddleware(null);
2321
2424
  // Clear the redirect user when signOut is called
2322
2425
  if (this.redirectPersistenceManager || this._popupRedirectResolver) {
2323
2426
  await this._setRedirectUser(null);
2324
2427
  }
2325
- return this._updateCurrentUser(null);
2428
+ // Prevent callbacks from being called again in _updateCurrentUser, as
2429
+ // they were already called in the first line.
2430
+ return this._updateCurrentUser(null, /* skipBeforeStateCallbacks */ true);
2326
2431
  }
2327
2432
  setPersistence(persistence) {
2328
2433
  return this.queue(async () => {
@@ -2338,6 +2443,9 @@ class AuthImpl {
2338
2443
  onAuthStateChanged(nextOrObserver, error, completed) {
2339
2444
  return this.registerStateListener(this.authStateSubscription, nextOrObserver, error, completed);
2340
2445
  }
2446
+ beforeAuthStateChanged(callback, onAbort) {
2447
+ return this.beforeStateQueue.pushCallback(callback, onAbort);
2448
+ }
2341
2449
  onIdTokenChanged(nextOrObserver, error, completed) {
2342
2450
  return this.registerStateListener(this.idTokenSubscription, nextOrObserver, error, completed);
2343
2451
  }
@@ -5543,6 +5651,19 @@ function setPersistence(auth, persistence) {
5543
5651
  function onIdTokenChanged(auth, nextOrObserver, error, completed) {
5544
5652
  return getModularInstance(auth).onIdTokenChanged(nextOrObserver, error, completed);
5545
5653
  }
5654
+ /**
5655
+ * Adds a blocking callback that runs before an auth state change
5656
+ * sets a new user.
5657
+ *
5658
+ * @param auth - The {@link Auth} instance.
5659
+ * @param callback - callback triggered before new user value is set.
5660
+ * If this throws, it blocks the user from being set.
5661
+ * @param onAbort - callback triggered if a later `beforeAuthStateChanged()`
5662
+ * callback throws, allowing you to undo any side effects.
5663
+ */
5664
+ function beforeAuthStateChanged(auth, callback, onAbort) {
5665
+ return getModularInstance(auth).beforeAuthStateChanged(callback, onAbort);
5666
+ }
5546
5667
  /**
5547
5668
  * Adds an observer for changes to the user's sign-in state.
5548
5669
  *
@@ -5817,7 +5938,7 @@ function multiFactor(user) {
5817
5938
  }
5818
5939
 
5819
5940
  var name = "@firebase/auth";
5820
- var version = "0.19.12";
5941
+ var version = "0.20.0";
5821
5942
 
5822
5943
  /**
5823
5944
  * @license
@@ -6043,5 +6164,5 @@ class PhoneMultiFactorGenerator {
6043
6164
  // auth.setPersistence(persistence) are covered.
6044
6165
  AuthImpl.prototype.setPersistence = async () => { };
6045
6166
 
6046
- export { sendPasswordResetEmail as $, ActionCodeOperation as A, prodErrorMap as B, AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY as C, initializeAuth as D, connectAuthEmulator as E, FactorId as F, AuthCredential as G, EmailAuthCredential as H, OAuthCredential as I, PhoneAuthCredential as J, inMemoryPersistence as K, EmailAuthProvider as L, FacebookAuthProvider as M, GoogleAuthProvider as N, OperationType as O, PhoneAuthProvider as P, GithubAuthProvider as Q, RecaptchaVerifier as R, SignInMethod as S, OAuthProvider as T, SAMLAuthProvider as U, TwitterAuthProvider as V, signInAnonymously as W, signInWithCredential as X, linkWithCredential as Y, reauthenticateWithCredential as Z, signInWithCustomToken as _, browserSessionPersistence as a, confirmPasswordReset as a0, applyActionCode as a1, checkActionCode as a2, verifyPasswordResetCode as a3, createUserWithEmailAndPassword as a4, signInWithEmailAndPassword as a5, sendSignInLinkToEmail as a6, isSignInWithEmailLink as a7, signInWithEmailLink as a8, fetchSignInMethodsForEmail as a9, _emulatorUrl as aA, _performApiRequest as aB, _isIOS7Or8 as aC, _isIOS as aD, _isAndroid as aE, _createError as aF, _isSafari as aG, _isIframe as aH, _isMobileBrowser as aI, _isIE10 as aJ, UserImpl as aK, AuthImpl as aL, _getClientVersion as aM, FetchProvider as aN, SAMLAuthCredential as aO, sendEmailVerification as aa, verifyBeforeUpdateEmail as ab, ActionCodeURL as ac, parseActionCodeURL as ad, updateProfile as ae, updateEmail as af, updatePassword as ag, getIdToken as ah, getIdTokenResult as ai, unlink as aj, getAdditionalUserInfo as ak, reload as al, getMultiFactorResolver as am, multiFactor as an, _getInstance as ao, _assert as ap, _signInWithCredential as aq, _reauthenticate as ar, _link as as, signInWithIdp as at, _fail as au, debugAssert as av, _persistenceKeyName as aw, _castAuth as ax, FederatedAuthProvider as ay, BaseOAuthProvider as az, browserLocalPersistence as b, signInWithPopup as c, linkWithPopup as d, reauthenticateWithPopup as e, signInWithRedirect as f, linkWithRedirect as g, reauthenticateWithRedirect as h, indexedDBLocalPersistence as i, getRedirectResult as j, browserPopupRedirectResolver as k, linkWithPhoneNumber as l, PhoneMultiFactorGenerator as m, getAuth as n, ProviderId as o, setPersistence as p, onIdTokenChanged as q, reauthenticateWithPhoneNumber as r, signInWithPhoneNumber as s, onAuthStateChanged as t, updatePhoneNumber as u, useDeviceLanguage as v, updateCurrentUser as w, signOut as x, deleteUser as y, debugErrorMap as z };
6047
- //# sourceMappingURL=index-d709908a.js.map
6167
+ export { signInWithCustomToken as $, ActionCodeOperation as A, debugErrorMap as B, prodErrorMap as C, AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY as D, initializeAuth as E, FactorId as F, connectAuthEmulator as G, AuthCredential as H, EmailAuthCredential as I, OAuthCredential as J, PhoneAuthCredential as K, inMemoryPersistence as L, EmailAuthProvider as M, FacebookAuthProvider as N, OperationType as O, PhoneAuthProvider as P, GoogleAuthProvider as Q, RecaptchaVerifier as R, SignInMethod as S, GithubAuthProvider as T, OAuthProvider as U, SAMLAuthProvider as V, TwitterAuthProvider as W, signInAnonymously as X, signInWithCredential as Y, linkWithCredential as Z, reauthenticateWithCredential as _, browserSessionPersistence as a, sendPasswordResetEmail as a0, confirmPasswordReset as a1, applyActionCode as a2, checkActionCode as a3, verifyPasswordResetCode as a4, createUserWithEmailAndPassword as a5, signInWithEmailAndPassword as a6, sendSignInLinkToEmail as a7, isSignInWithEmailLink as a8, signInWithEmailLink as a9, BaseOAuthProvider as aA, _emulatorUrl as aB, _performApiRequest as aC, _isIOS7Or8 as aD, _isIOS as aE, _isAndroid as aF, _createError as aG, _isSafari as aH, _isIframe as aI, _isMobileBrowser as aJ, _isIE10 as aK, UserImpl as aL, AuthImpl as aM, _getClientVersion as aN, FetchProvider as aO, SAMLAuthCredential as aP, fetchSignInMethodsForEmail as aa, sendEmailVerification as ab, verifyBeforeUpdateEmail as ac, ActionCodeURL as ad, parseActionCodeURL as ae, updateProfile as af, updateEmail as ag, updatePassword as ah, getIdToken as ai, getIdTokenResult as aj, unlink as ak, getAdditionalUserInfo as al, reload as am, getMultiFactorResolver as an, multiFactor as ao, _getInstance as ap, _assert as aq, _signInWithCredential as ar, _reauthenticate as as, _link as at, signInWithIdp as au, _fail as av, debugAssert as aw, _persistenceKeyName as ax, _castAuth as ay, FederatedAuthProvider as az, browserLocalPersistence as b, signInWithPopup as c, linkWithPopup as d, reauthenticateWithPopup as e, signInWithRedirect as f, linkWithRedirect as g, reauthenticateWithRedirect as h, indexedDBLocalPersistence as i, getRedirectResult as j, browserPopupRedirectResolver as k, linkWithPhoneNumber as l, PhoneMultiFactorGenerator as m, getAuth as n, ProviderId as o, setPersistence as p, onIdTokenChanged as q, reauthenticateWithPhoneNumber as r, signInWithPhoneNumber as s, beforeAuthStateChanged as t, updatePhoneNumber as u, onAuthStateChanged as v, useDeviceLanguage as w, updateCurrentUser as x, signOut as y, deleteUser as z };
6168
+ //# sourceMappingURL=index-c85cf380.js.map