diff --git a/.changeset/hot-experts-talk.md b/.changeset/hot-experts-talk.md new file mode 100644 index 00000000000..2903ce42919 --- /dev/null +++ b/.changeset/hot-experts-talk.md @@ -0,0 +1,5 @@ +--- +'@firebase/auth': patch +--- + +Support TOTP as a multi-factor option in Firebase Auth/GCIP. diff --git a/common/api-review/auth.api.md b/common/api-review/auth.api.md index 045b64bcf19..5b147491212 100644 --- a/common/api-review/auth.api.md +++ b/common/api-review/auth.api.md @@ -361,6 +361,7 @@ export class FacebookAuthProvider extends BaseOAuthProvider { // @public export const FactorId: { readonly PHONE: "phone"; + readonly TOTP: "totp"; }; // @public @@ -745,6 +746,41 @@ export function signInWithRedirect(auth: Auth, provider: AuthProvider, resolver? // @public export function signOut(auth: Auth): Promise; +// @public +export interface TotpMultiFactorAssertion extends MultiFactorAssertion { +} + +// @public +export class TotpMultiFactorGenerator { + static assertionForEnrollment(secret: TotpSecret, oneTimePassword: string): TotpMultiFactorAssertion; + static assertionForSignIn(enrollmentId: string, oneTimePassword: string): TotpMultiFactorAssertion; + // Warning: (ae-forgotten-export) The symbol "FactorId" needs to be exported by the entry point index.d.ts + static FACTOR_ID: FactorId_2; + static generateSecret(session: MultiFactorSession): Promise; +} + +// @public +export interface TotpMultiFactorInfo extends MultiFactorInfo { +} + +// @public +export class TotpSecret { + readonly codeIntervalSeconds: number; + readonly codeLength: number; + readonly enrollmentCompletionDeadline: string; + // Warning: (ae-forgotten-export) The symbol "StartTotpMfaEnrollmentResponse" needs to be exported by the entry point index.d.ts + // + // @internal (undocumented) + static _fromStartTotpMfaEnrollmentResponse(response: StartTotpMfaEnrollmentResponse, auth: AuthInternal): TotpSecret; + generateQrCodeUrl(accountName?: string, issuer?: string): string; + readonly hashingAlgorithm: string; + // Warning: (ae-forgotten-export) The symbol "TotpVerificationInfo" needs to be exported by the entry point index.d.ts + // + // @internal (undocumented) + _makeTotpVerificationInfo(otp: string): TotpVerificationInfo; + readonly secretKey: string; + } + // @public export class TwitterAuthProvider extends BaseOAuthProvider { constructor(); diff --git a/docs-devsite/auth.md b/docs-devsite/auth.md index f0f9029c225..d3b3572df51 100644 --- a/docs-devsite/auth.md +++ b/docs-devsite/auth.md @@ -93,6 +93,8 @@ Firebase Authentication | [PhoneMultiFactorGenerator](./auth.phonemultifactorgenerator.md#phonemultifactorgenerator_class) | Provider for generating a [PhoneMultiFactorAssertion](./auth.phonemultifactorassertion.md#phonemultifactorassertion_interface). | | [RecaptchaVerifier](./auth.recaptchaverifier.md#recaptchaverifier_class) | An [reCAPTCHA](https://www.google.com/recaptcha/)-based application verifier. | | [SAMLAuthProvider](./auth.samlauthprovider.md#samlauthprovider_class) | An [AuthProvider](./auth.authprovider.md#authprovider_interface) for SAML. | +| [TotpMultiFactorGenerator](./auth.totpmultifactorgenerator.md#totpmultifactorgenerator_class) | Provider for generating a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface). | +| [TotpSecret](./auth.totpsecret.md#totpsecret_class) | Provider for generating a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface).Stores the shared secret key and other parameters to generate time-based OTPs. Implements methods to retrieve the shared secret key and generate a QR code URL. | | [TwitterAuthProvider](./auth.twitterauthprovider.md#twitterauthprovider_class) | Provider for generating an [OAuthCredential](./auth.oauthcredential.md#oauthcredential_class) for [ProviderId](./auth.md#providerid).TWITTER. | ## Interfaces @@ -130,6 +132,8 @@ Firebase Authentication | [PopupRedirectResolver](./auth.popupredirectresolver.md#popupredirectresolver_interface) | A resolver used for handling DOM specific operations like [signInWithPopup()](./auth.md#signinwithpopup) or [signInWithRedirect()](./auth.md#signinwithredirect). | | [ReactNativeAsyncStorage](./auth.reactnativeasyncstorage.md#reactnativeasyncstorage_interface) | Interface for a supplied AsyncStorage. | | [RecaptchaParameters](./auth.recaptchaparameters.md#recaptchaparameters_interface) | Interface representing reCAPTCHA parameters.See the \[reCAPTCHA docs\](https://developers.google.com/recaptcha/docs/display\#render\_param) for the list of accepted parameters. All parameters are accepted except for sitekey: Firebase Auth provisions a reCAPTCHA for each project and will configure the site key upon rendering.For an invisible reCAPTCHA, set the size key to invisible. | +| [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) | The class for asserting ownership of a TOTP second factor. Provided by [TotpMultiFactorGenerator.assertionForEnrollment()](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforenrollment) and [TotpMultiFactorGenerator.assertionForSignIn()](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforsignin). | +| [TotpMultiFactorInfo](./auth.totpmultifactorinfo.md#totpmultifactorinfo_interface) | The subclass of the [MultiFactorInfo](./auth.multifactorinfo.md#multifactorinfo_interface) interface for TOTP second factors. The factorId of this second factor is [FactorId](./auth.md#factorid).TOTP. | | [User](./auth.user.md#user_interface) | A user account. | | [UserCredential](./auth.usercredential.md#usercredential_interface) | A structure containing a [User](./auth.user.md#user_interface), the [OperationType](./auth.md#operationtype), and the provider ID. | | [UserInfo](./auth.userinfo.md#userinfo_interface) | User profile information, visible only to the Firebase project's apps. | @@ -1855,6 +1859,7 @@ An enum of factors that may be used for multifactor authentication. ```typescript FactorId: { readonly PHONE: "phone"; + readonly TOTP: "totp"; } ``` diff --git a/docs-devsite/auth.totpmultifactorassertion.md b/docs-devsite/auth.totpmultifactorassertion.md new file mode 100644 index 00000000000..ef4f6f34fd5 --- /dev/null +++ b/docs-devsite/auth.totpmultifactorassertion.md @@ -0,0 +1,21 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# TotpMultiFactorAssertion interface +The class for asserting ownership of a TOTP second factor. Provided by [TotpMultiFactorGenerator.assertionForEnrollment()](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforenrollment) and [TotpMultiFactorGenerator.assertionForSignIn()](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforsignin). + +Signature: + +```typescript +export interface TotpMultiFactorAssertion extends MultiFactorAssertion +``` +Extends: [MultiFactorAssertion](./auth.multifactorassertion.md#multifactorassertion_interface) + diff --git a/docs-devsite/auth.totpmultifactorgenerator.md b/docs-devsite/auth.totpmultifactorgenerator.md new file mode 100644 index 00000000000..93b7c485f40 --- /dev/null +++ b/docs-devsite/auth.totpmultifactorgenerator.md @@ -0,0 +1,112 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# TotpMultiFactorGenerator class +Provider for generating a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface). + +Signature: + +```typescript +export declare class TotpMultiFactorGenerator +``` + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [FACTOR\_ID](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorfactor_id) | static | FactorId | The identifier of the TOTP second factor: totp. | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [assertionForEnrollment(secret, oneTimePassword)](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforenrollment) | static | Provides a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) to confirm ownership of the TOTP (time-based one-time password) second factor. This assertion is used to complete enrollment in TOTP second factor. | +| [assertionForSignIn(enrollmentId, oneTimePassword)](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforsignin) | static | Provides a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) to confirm ownership of the TOTP second factor. This assertion is used to complete signIn with TOTP as the second factor. | +| [generateSecret(session)](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorgeneratesecret) | static | Returns a promise to [TotpSecret](./auth.totpsecret.md#totpsecret_class) which contains the TOTP shared secret key and other parameters. Creates a TOTP secret as part of enrolling a TOTP second factor. Used for generating a QR code URL or inputting into a TOTP app. This method uses the auth instance corresponding to the user in the multiFactorSession. | + +## TotpMultiFactorGenerator.FACTOR\_ID + +The identifier of the TOTP second factor: `totp`. + +Signature: + +```typescript +static FACTOR_ID: FactorId; +``` + +## TotpMultiFactorGenerator.assertionForEnrollment() + +Provides a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) to confirm ownership of the TOTP (time-based one-time password) second factor. This assertion is used to complete enrollment in TOTP second factor. + +Signature: + +```typescript +static assertionForEnrollment(secret: TotpSecret, oneTimePassword: string): TotpMultiFactorAssertion; +``` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| secret | [TotpSecret](./auth.totpsecret.md#totpsecret_class) | A [TotpSecret](./auth.totpsecret.md#totpsecret_class) containing the shared secret key and other TOTP parameters. | +| oneTimePassword | string | One-time password from TOTP App. | + +Returns: + +[TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) + +A [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) which can be used with [MultiFactorUser.enroll()](./auth.multifactoruser.md#multifactoruserenroll). + +## TotpMultiFactorGenerator.assertionForSignIn() + +Provides a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) to confirm ownership of the TOTP second factor. This assertion is used to complete signIn with TOTP as the second factor. + +Signature: + +```typescript +static assertionForSignIn(enrollmentId: string, oneTimePassword: string): TotpMultiFactorAssertion; +``` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| enrollmentId | string | identifies the enrolled TOTP second factor. | +| oneTimePassword | string | One-time password from TOTP App. | + +Returns: + +[TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) + +A [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) which can be used with [MultiFactorResolver.resolveSignIn()](./auth.multifactorresolver.md#multifactorresolverresolvesignin). + +## TotpMultiFactorGenerator.generateSecret() + +Returns a promise to [TotpSecret](./auth.totpsecret.md#totpsecret_class) which contains the TOTP shared secret key and other parameters. Creates a TOTP secret as part of enrolling a TOTP second factor. Used for generating a QR code URL or inputting into a TOTP app. This method uses the auth instance corresponding to the user in the multiFactorSession. + +Signature: + +```typescript +static generateSecret(session: MultiFactorSession): Promise; +``` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| session | [MultiFactorSession](./auth.multifactorsession.md#multifactorsession_interface) | The [MultiFactorSession](./auth.multifactorsession.md#multifactorsession_interface) that the user is part of. | + +Returns: + +Promise<[TotpSecret](./auth.totpsecret.md#totpsecret_class)> + +A promise to [TotpSecret](./auth.totpsecret.md#totpsecret_class). + diff --git a/docs-devsite/auth.totpmultifactorinfo.md b/docs-devsite/auth.totpmultifactorinfo.md new file mode 100644 index 00000000000..116474ec850 --- /dev/null +++ b/docs-devsite/auth.totpmultifactorinfo.md @@ -0,0 +1,21 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# TotpMultiFactorInfo interface +The subclass of the [MultiFactorInfo](./auth.multifactorinfo.md#multifactorinfo_interface) interface for TOTP second factors. The `factorId` of this second factor is [FactorId](./auth.md#factorid).TOTP. + +Signature: + +```typescript +export interface TotpMultiFactorInfo extends MultiFactorInfo +``` +Extends: [MultiFactorInfo](./auth.multifactorinfo.md#multifactorinfo_interface) + diff --git a/docs-devsite/auth.totpsecret.md b/docs-devsite/auth.totpsecret.md new file mode 100644 index 00000000000..8e040735b2d --- /dev/null +++ b/docs-devsite/auth.totpsecret.md @@ -0,0 +1,111 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# TotpSecret class +Provider for generating a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface). + +Stores the shared secret key and other parameters to generate time-based OTPs. Implements methods to retrieve the shared secret key and generate a QR code URL. + +Signature: + +```typescript +export declare class TotpSecret +``` + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [codeIntervalSeconds](./auth.totpsecret.md#totpsecretcodeintervalseconds) | | number | The interval (in seconds) when the OTP codes should change. | +| [codeLength](./auth.totpsecret.md#totpsecretcodelength) | | number | Length of the one-time passwords to be generated. | +| [enrollmentCompletionDeadline](./auth.totpsecret.md#totpsecretenrollmentcompletiondeadline) | | string | The timestamp (UTC string) by which TOTP enrollment should be completed. | +| [hashingAlgorithm](./auth.totpsecret.md#totpsecrethashingalgorithm) | | string | Hashing algorithm used. | +| [secretKey](./auth.totpsecret.md#totpsecretsecretkey) | | string | Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs. | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [generateQrCodeUrl(accountName, issuer)](./auth.totpsecret.md#totpsecretgenerateqrcodeurl) | | Returns a QR code URL as described in https://github.com/google/google-authenticator/wiki/Key-Uri-Format This can be displayed to the user as a QR code to be scanned into a TOTP app like Google Authenticator. If the optional parameters are unspecified, an accountName of and issuer of are used. | + +## TotpSecret.codeIntervalSeconds + +The interval (in seconds) when the OTP codes should change. + +Signature: + +```typescript +readonly codeIntervalSeconds: number; +``` + +## TotpSecret.codeLength + +Length of the one-time passwords to be generated. + +Signature: + +```typescript +readonly codeLength: number; +``` + +## TotpSecret.enrollmentCompletionDeadline + +The timestamp (UTC string) by which TOTP enrollment should be completed. + +Signature: + +```typescript +readonly enrollmentCompletionDeadline: string; +``` + +## TotpSecret.hashingAlgorithm + +Hashing algorithm used. + +Signature: + +```typescript +readonly hashingAlgorithm: string; +``` + +## TotpSecret.secretKey + +Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs. + +Signature: + +```typescript +readonly secretKey: string; +``` + +## TotpSecret.generateQrCodeUrl() + +Returns a QR code URL as described in https://github.com/google/google-authenticator/wiki/Key-Uri-Format This can be displayed to the user as a QR code to be scanned into a TOTP app like Google Authenticator. If the optional parameters are unspecified, an accountName of and issuer of are used. + +Signature: + +```typescript +generateQrCodeUrl(accountName?: string, issuer?: string): string; +``` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| accountName | string | the name of the account/app along with a user identifier. | +| issuer | string | issuer of the TOTP (likely the app name). | + +Returns: + +string + +A QR code URL string. + diff --git a/packages/auth/README.md b/packages/auth/README.md index 0592fa595a7..ad8ca35d5eb 100644 --- a/packages/auth/README.md +++ b/packages/auth/README.md @@ -17,6 +17,7 @@ host of npm scripts to run these tests. The most important commands are: | `yarn test::unit:debug` | Runs \ unit tests, auto-watching for file system changes | | `yarn test::integration` | Runs only integration tests against the live environment | | `yarn test::integration:local` | Runs all headless \ integration tests against the emulator (more below) | +| `yarn test:browser:integration:prodbackend` | Runs TOTP MFA integration tests against the backend (more below) | Where \ is "browser" or "node". There are also cordova tests, but they are not broken into such granular details. Check out `package.json` for more. @@ -46,6 +47,25 @@ you would simply execute the following command: firebase emulators:exec --project foo-bar --only auth "yarn test:integration:local" ``` +### Integration testing with the production backend + +Currently, MFA TOTP tests only run against the production backend (since they are not supported on the emulator yet). +Running against the backend also makes it a more reliable end-to-end test. + +The TOTP tests require the following email/password combination to exist in the project, so if you are running this test against your test project, please create this user: + +'totpuser-donotdelete@test.com', 'password' + +You also need to verify this email address, in order to use MFA. This can be done with a curl command like this: + +``` +curl -H "Authorization: Bearer $(gcloud auth print-access-token)" -H "Content-Type: application/json" -H "X-Goog-User-Project: ${PROJECT_ID}" -X POST https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode -d '{ + "email": "totpuser-donotdelete@test.com", + "requestType": "VERIFY_EMAIL", + "returnOobLink": true, + }' +``` + ### Selenium Webdriver tests These tests assume that you have both Firefox and Chrome installed on your diff --git a/packages/auth/demo/README.md b/packages/auth/demo/README.md index beb5a800bc5..f29127ab074 100644 --- a/packages/auth/demo/README.md +++ b/packages/auth/demo/README.md @@ -45,12 +45,21 @@ in the `config.js` file. Before deploying, you may need to build the auth package: ```bash +cd auth/demo yarn yarn build:deps ``` This can take some time, and you only need to do it if you've modified the auth package. +You can optionally clear the cache and rebuild using: + +```bash +cd auth/demo +rm -rf node_modules yarn.lock +yarn build:deps +``` + To run the app locally, simply issue the following command in the `auth/demo` directory: ```bash diff --git a/packages/auth/demo/public/index.html b/packages/auth/demo/public/index.html index 624b6e3c0e7..d098860f216 100644 --- a/packages/auth/demo/public/index.html +++ b/packages/auth/demo/public/index.html @@ -229,6 +229,18 @@ + +
Set Tenant
+
+ + +
+
Sign Up
@@ -487,6 +499,12 @@ Phone +
  • + + TOTP + +
  • @@ -504,7 +522,27 @@ class="form-control" placeholder="Display Name" /> + + +
    +
    +
    + +
    + + + +
    + + +
    @@ -733,6 +771,17 @@
    + +