diff --git a/common/api-review/auth-exp.api.md b/common/api-review/auth-exp.api.md index 06b87ad9b20..85f36db2ea9 100644 --- a/common/api-review/auth-exp.api.md +++ b/common/api-review/auth-exp.api.md @@ -185,20 +185,17 @@ export const debugErrorMap: AuthErrorMap; // @public export function deleteUser(user: User): Promise; -// @public (undocumented) +// @public export interface Dependencies { - // (undocumented) errorMap?: AuthErrorMap; - // (undocumented) persistence?: Persistence | Persistence[]; - // (undocumented) popupRedirectResolver?: PopupRedirectResolver; } // @public export class EmailAuthCredential extends AuthCredential { - // (undocumented) - readonly email: string; + // @internal (undocumented) + readonly _email: string; // @internal (undocumented) static _fromEmailAndCode(email: string, oobCode: string, tenantId?: string | null): EmailAuthCredential; // @internal (undocumented) @@ -210,10 +207,10 @@ export class EmailAuthCredential extends AuthCredential { _getReauthenticationResolver(auth: AuthInternal): Promise; // @internal (undocumented) _linkToIdToken(auth: AuthInternal, idToken: string): Promise; - // (undocumented) - readonly password: string; - // (undocumented) - readonly tenantId: string | null; + // @internal (undocumented) + readonly _password: string; + // @internal (undocumented) + readonly _tenantId: string | null; toJSON(): object; } @@ -301,7 +298,7 @@ export interface IdTokenResult { // @public export const indexedDBLocalPersistence: Persistence; -// @public (undocumented) +// @public export function initializeAuth(app: FirebaseApp, deps?: Dependencies): Auth; // @public @@ -397,7 +394,6 @@ export interface OAuthCredentialOptions { export class OAuthProvider extends BaseOAuthProvider { credential(params: OAuthCredentialOptions): OAuthCredential; static credentialFromError(error: FirebaseError): OAuthCredential | null; - // (undocumented) static credentialFromJSON(json: object | string): OAuthCredential; static credentialFromResult(userCredential: UserCredential): OAuthCredential | null; } @@ -460,7 +456,6 @@ export class PhoneAuthCredential extends AuthCredential { export class PhoneAuthProvider { constructor(auth: Auth); static credential(verificationId: string, verificationCode: string): PhoneAuthCredential; - // (undocumented) static credentialFromResult(userCredential: UserCredential): AuthCredential | null; static readonly PHONE_SIGN_IN_METHOD = SignInMethod.PHONE; static readonly PROVIDER_ID = ProviderId.PHONE; @@ -507,23 +502,17 @@ export const prodErrorMap: AuthErrorMap; // @public export const enum ProviderId { - // (undocumented) + // @internal (undocumented) ANONYMOUS = "anonymous", - // (undocumented) + // @internal (undocumented) CUSTOM = "custom", - // (undocumented) FACEBOOK = "facebook.com", - // (undocumented) + // @internal (undocumented) FIREBASE = "firebase", - // (undocumented) GITHUB = "github.com", - // (undocumented) GOOGLE = "google.com", - // (undocumented) PASSWORD = "password", - // (undocumented) PHONE = "phone", - // (undocumented) TWITTER = "twitter.com" } @@ -572,11 +561,8 @@ export function reload(user: User): Promise; // @public export class SAMLAuthProvider extends FederatedAuthProvider { constructor(providerId: string); - // (undocumented) static credentialFromError(error: FirebaseError): AuthCredential | null; - // (undocumented) static credentialFromJSON(json: string | object): AuthCredential; - // (undocumented) static credentialFromResult(userCredential: UserCredential): AuthCredential | null; } @@ -597,21 +583,14 @@ export function signInAnonymously(auth: Auth): Promise; // @public export const enum SignInMethod { - // (undocumented) + // @internal (undocumented) ANONYMOUS = "anonymous", - // (undocumented) EMAIL_LINK = "emailLink", - // (undocumented) EMAIL_PASSWORD = "password", - // (undocumented) FACEBOOK = "facebook.com", - // (undocumented) GITHUB = "github.com", - // (undocumented) GOOGLE = "google.com", - // (undocumented) PHONE = "phone", - // (undocumented) TWITTER = "twitter.com" } @@ -645,9 +624,7 @@ export class TwitterAuthProvider extends BaseOAuthProvider { static credential(token: string, secret: string): OAuthCredential; static credentialFromError(error: FirebaseError): OAuthCredential | null; static credentialFromResult(userCredential: UserCredential): OAuthCredential | null; - // (undocumented) static readonly PROVIDER_ID = ProviderId.TWITTER; - // (undocumented) static readonly TWITTER_SIGN_IN_METHOD = SignInMethod.TWITTER; } diff --git a/packages-exp/auth-exp/src/core/action_code_url.ts b/packages-exp/auth-exp/src/core/action_code_url.ts index 6ed7e5f3ad0..6a40b43416c 100644 --- a/packages-exp/auth-exp/src/core/action_code_url.ts +++ b/packages-exp/auth-exp/src/core/action_code_url.ts @@ -154,7 +154,8 @@ export class ActionCodeURL { } /** - * {@inheritDoc ActionCodeURL.parseLink} + * Parses the email action link string and returns an {@link ActionCodeURL} if + * the link is valid, otherwise returns null. * * @public */ diff --git a/packages-exp/auth-exp/src/core/auth/initialize.ts b/packages-exp/auth-exp/src/core/auth/initialize.ts index 09b13c5d33d..32e254ad84a 100644 --- a/packages-exp/auth-exp/src/core/auth/initialize.ts +++ b/packages-exp/auth-exp/src/core/auth/initialize.ts @@ -24,7 +24,31 @@ import { _fail } from '../util/assert'; import { _getInstance } from '../util/instantiator'; import { AuthImpl } from './auth_impl'; -/** @public */ +/** + * Initializes an Auth instance with fine-grained control over + * {@link Dependencies}. + * + * @remarks + * + * This function allows more control over the Auth instance than + * {@link getAuth}. `getAuth` uses platform-specific defaults to supply + * the {@link Dependencies}. In general, `getAuth` is the easiest way to + * initialize Auth and works for most use cases. Use `initializeAuth` if you + * need control over which persistence layer is used, or to minimize bundle + * size if you're not using either `signInWithPopup` or `signInWithRedirect`. + * + * For example, if your app only uses anonymous accounts and you only want + * accounts saved for the current session, initialize Auth with: + * + * ```js + * const auth = initializeAuth(app, { + * persistence: browserSessionPersistence, + * popupRedirectResolver: undefined, + * }); + * ``` + * + * @public + */ export function initializeAuth(app: FirebaseApp, deps?: Dependencies): Auth { const provider = _getProvider(app, 'auth-exp'); diff --git a/packages-exp/auth-exp/src/core/credentials/email.ts b/packages-exp/auth-exp/src/core/credentials/email.ts index 8a152c3e2e8..9ac898c3f93 100644 --- a/packages-exp/auth-exp/src/core/credentials/email.ts +++ b/packages-exp/auth-exp/src/core/credentials/email.ts @@ -42,10 +42,13 @@ import { AuthCredential } from './auth_credential'; export class EmailAuthCredential extends AuthCredential { /** @internal */ private constructor( - readonly email: string, - readonly password: string, + /** @internal */ + readonly _email: string, + /** @internal */ + readonly _password: string, signInMethod: SignInMethod, - readonly tenantId: string | null = null + /** @internal */ + readonly _tenantId: string | null = null ) { super(ProviderId.PASSWORD, signInMethod); } @@ -79,10 +82,10 @@ export class EmailAuthCredential extends AuthCredential { /** {@inheritdoc AuthCredential.toJSON} */ toJSON(): object { return { - email: this.email, - password: this.password, + email: this._email, + password: this._password, signInMethod: this.signInMethod, - tenantId: this.tenantId + tenantId: this._tenantId }; } @@ -112,13 +115,13 @@ export class EmailAuthCredential extends AuthCredential { case SignInMethod.EMAIL_PASSWORD: return signInWithPassword(auth, { returnSecureToken: true, - email: this.email, - password: this.password + email: this._email, + password: this._password }); case SignInMethod.EMAIL_LINK: return signInWithEmailLink(auth, { - email: this.email, - oobCode: this.password + email: this._email, + oobCode: this._password }); default: _fail(auth, AuthErrorCode.INTERNAL_ERROR); @@ -135,14 +138,14 @@ export class EmailAuthCredential extends AuthCredential { return updateEmailPassword(auth, { idToken, returnSecureToken: true, - email: this.email, - password: this.password + email: this._email, + password: this._password }); case SignInMethod.EMAIL_LINK: return signInWithEmailLinkForLinking(auth, { idToken, - email: this.email, - oobCode: this.password + email: this._email, + oobCode: this._password }); default: _fail(auth, AuthErrorCode.INTERNAL_ERROR); diff --git a/packages-exp/auth-exp/src/core/credentials/phone.ts b/packages-exp/auth-exp/src/core/credentials/phone.ts index d10539d0148..03117d3e63a 100644 --- a/packages-exp/auth-exp/src/core/credentials/phone.ts +++ b/packages-exp/auth-exp/src/core/credentials/phone.ts @@ -121,14 +121,7 @@ export class PhoneAuthCredential extends AuthCredential { return obj; } - /** - * Static method to deserialize a JSON representation of an object into an {@link AuthCredential}. - * - * @param json - Either `object` or the stringified representation of the object. When string is - * provided, `JSON.parse` would be called first. - * - * @returns If the JSON input does not represent an {@link AuthCredential}, null is returned. - */ + /** Generates a phone credential based on a plain object or a JSON string. */ static fromJSON(json: object | string): PhoneAuthCredential | null { if (typeof json === 'string') { json = JSON.parse(json); diff --git a/packages-exp/auth-exp/src/core/providers/email.test.ts b/packages-exp/auth-exp/src/core/providers/email.test.ts index 9fc94392a1a..7046d1006ae 100644 --- a/packages-exp/auth-exp/src/core/providers/email.test.ts +++ b/packages-exp/auth-exp/src/core/providers/email.test.ts @@ -33,8 +33,8 @@ describe('core/providers/email', () => { 'some-email', 'some-password' ); - expect(credential.email).to.eq('some-email'); - expect(credential.password).to.eq('some-password'); + expect(credential._email).to.eq('some-email'); + expect(credential._password).to.eq('some-password'); expect(credential.providerId).to.eq(ProviderId.PASSWORD); expect(credential.signInMethod).to.eq(SignInMethod.EMAIL_PASSWORD); }); @@ -54,8 +54,8 @@ describe('core/providers/email', () => { 'some-email', actionLink ); - expect(credential.email).to.eq('some-email'); - expect(credential.password).to.eq('CODE'); + expect(credential._email).to.eq('some-email'); + expect(credential._password).to.eq('CODE'); expect(credential.providerId).to.eq(ProviderId.PASSWORD); expect(credential.signInMethod).to.eq(SignInMethod.EMAIL_LINK); }); diff --git a/packages-exp/auth-exp/src/core/providers/oauth.ts b/packages-exp/auth-exp/src/core/providers/oauth.ts index 418e752e1a9..be8a8a6e985 100644 --- a/packages-exp/auth-exp/src/core/providers/oauth.ts +++ b/packages-exp/auth-exp/src/core/providers/oauth.ts @@ -128,6 +128,10 @@ export abstract class BaseOAuthProvider * @public */ export class OAuthProvider extends BaseOAuthProvider { + /** + * Creates an {@link OAuthCredential} from a JSON string or a plain object. + * @param json A plain object or a JSON string + */ static credentialFromJSON(json: object | string): OAuthCredential { const obj = typeof json === 'string' ? JSON.parse(json) : json; _assert( diff --git a/packages-exp/auth-exp/src/core/providers/saml.ts b/packages-exp/auth-exp/src/core/providers/saml.ts index 9893f44fd3a..e4378bb6d48 100644 --- a/packages-exp/auth-exp/src/core/providers/saml.ts +++ b/packages-exp/auth-exp/src/core/providers/saml.ts @@ -46,6 +46,22 @@ export class SAMLAuthProvider extends FederatedAuthProvider { super(providerId); } + /** + * Generates an {@link AuthCredential} from a {@link UserCredential} after a + * successful SAML flow completes. + * + * @remarks + * + * For example, to get an {@link AuthCredential}, you could write the + * following code: + * + * ```js + * const userCredential = await signInWithPopup(auth, samlProvider); + * const credential = SAMLAuthProvider.credentialFromResult(userCredential); + * ``` + * + * @param userCredential + */ static credentialFromResult( userCredential: UserCredential ): AuthCredential | null { @@ -54,12 +70,22 @@ export class SAMLAuthProvider extends FederatedAuthProvider { ); } + /** + * Used to extract the underlying {@link OAuthCredential} from a {@link AuthError} which was + * thrown during a sign-in, link, or reauthenticate operation. + * + * @param userCredential - The user credential. + */ static credentialFromError(error: FirebaseError): AuthCredential | null { return SAMLAuthProvider.samlCredentialFromTaggedObject( (error.customData || {}) as TaggedWithTokenResponse ); } + /** + * Creates an {@link AuthCredential} from a JSON string or a plain object. + * @param json A plain object or a JSON string + */ static credentialFromJSON(json: string | object): AuthCredential { const credential = SAMLAuthCredential.fromJSON(json); _assert(credential, AuthErrorCode.ARGUMENT_ERROR); diff --git a/packages-exp/auth-exp/src/core/providers/twitter.ts b/packages-exp/auth-exp/src/core/providers/twitter.ts index 745f12f38b7..1498dd6232a 100644 --- a/packages-exp/auth-exp/src/core/providers/twitter.ts +++ b/packages-exp/auth-exp/src/core/providers/twitter.ts @@ -85,7 +85,9 @@ import { BaseOAuthProvider } from './oauth'; * @public */ export class TwitterAuthProvider extends BaseOAuthProvider { + /** Always set to {@link SignInMethod.TWITTER}. */ static readonly TWITTER_SIGN_IN_METHOD = SignInMethod.TWITTER; + /** Always set to {@link ProviderId.TWITTER}. */ static readonly PROVIDER_ID = ProviderId.TWITTER; constructor() { diff --git a/packages-exp/auth-exp/src/core/strategies/email_link.ts b/packages-exp/auth-exp/src/core/strategies/email_link.ts index 156251bdd8e..31707296ef2 100644 --- a/packages-exp/auth-exp/src/core/strategies/email_link.ts +++ b/packages-exp/auth-exp/src/core/strategies/email_link.ts @@ -155,7 +155,7 @@ export async function signInWithEmailLink( // Check if the tenant ID in the email link matches the tenant ID on Auth // instance. _assert( - credential.tenantId === (authModular.tenantId || null), + credential._tenantId === (authModular.tenantId || null), authModular, AuthErrorCode.TENANT_ID_MISMATCH ); diff --git a/packages-exp/auth-exp/src/model/public_types.ts b/packages-exp/auth-exp/src/model/public_types.ts index d703b99f31c..ba55efd44ea 100644 --- a/packages-exp/auth-exp/src/model/public_types.ts +++ b/packages-exp/auth-exp/src/model/public_types.ts @@ -31,14 +31,23 @@ export { CompleteFn, ErrorFn, NextFn, Unsubscribe }; * @public */ export const enum ProviderId { + /** @internal */ ANONYMOUS = 'anonymous', + /** @internal */ CUSTOM = 'custom', + /** Facebook provider ID */ FACEBOOK = 'facebook.com', + /** @internal */ FIREBASE = 'firebase', + /** GitHub provider ID */ GITHUB = 'github.com', + /** Google provider ID */ GOOGLE = 'google.com', + /** Password provider */ PASSWORD = 'password', + /** Phone provider */ PHONE = 'phone', + /** Twitter provider ID */ TWITTER = 'twitter.com' } @@ -48,13 +57,21 @@ export const enum ProviderId { * @public */ export const enum SignInMethod { + /** @internal */ ANONYMOUS = 'anonymous', + /** Email link sign in method */ EMAIL_LINK = 'emailLink', + /** Email/password sign in method */ EMAIL_PASSWORD = 'password', + /** Facebook sign in method */ FACEBOOK = 'facebook.com', + /** GitHub sign in method */ GITHUB = 'github.com', + /** Google sign in method */ GOOGLE = 'google.com', + /** Phone sign in method */ PHONE = 'phone', + /** Twitter sign in method */ TWITTER = 'twitter.com' } @@ -1173,10 +1190,44 @@ export interface EmulatorConfig { export interface AuthErrorMap {} /** + * The dependencies that can be used to initialize an Auth instance. + * + * @remarks + * + * The modular SDK enables tree shaking by allowing explicit declarations of + * dependencies. For example, a web app does not need to include code that + * enables Cordova redirect sign in. That functionality is therefore split into + * {@link browserPopupRedirectResolver} and + * {@link cordovaPopupRedirectResolver}. The dependencies object is how Auth is + * configured to reduce bundle sizes. + * + * There are two ways to initialize an auth instance: {@link getAuth} and + * {@link initializeAuth}. `getAuth` initializes everything using + * platform-specific configurations, while `initializeAuth` takes a + * `Dependencies` object directly, giving you more control over what is used. + * * @public */ export interface Dependencies { + /** + * Which {@link Persistence} to use. If this is an array, the first + * `Persistence` that the device supports is used. The SDK searches for an + * existing account in order and, if one is found in a secondary + * `Persistence`, the account is moved to the primary `Persistence`. + * + * If no persistence is provided, the SDK falls back on + * {@link inMemoryPersistence}. + */ persistence?: Persistence | Persistence[]; + /** + * The {@link PopupRedirectResolver} to use. This value depends on the + * platform. Options are {@link browserPopupRedirectResolver} and + * {@link cordovaPopupRedirectResolver}. This field is optional if neither + * {@link signInWithPopup} or {@link signInWithRedirect} are being used. + */ popupRedirectResolver?: PopupRedirectResolver; + /** + * Which {@link AuthErrorMap} to use. + */ errorMap?: AuthErrorMap; } diff --git a/packages-exp/auth-exp/src/platform_browser/providers/phone.ts b/packages-exp/auth-exp/src/platform_browser/providers/phone.ts index 009b6333493..b78338183df 100644 --- a/packages-exp/auth-exp/src/platform_browser/providers/phone.ts +++ b/packages-exp/auth-exp/src/platform_browser/providers/phone.ts @@ -148,6 +148,10 @@ export class PhoneAuthProvider { ); } + /** + * Generates an {@link AuthCredential} from a {@link UserCredential}. + * @param userCredential + */ static credentialFromResult( userCredential: UserCredential ): AuthCredential | null {