Skip to content

Commit 58bae87

Browse files
authored
Support MFA TOTP in web SDK (#7146)
1 parent a00136c commit 58bae87

27 files changed

+1706
-23
lines changed

.changeset/hot-experts-talk.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/auth': patch
3+
---
4+
5+
Support TOTP as a multi-factor option in Firebase Auth/GCIP.

common/api-review/auth.api.md

+36
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ export class FacebookAuthProvider extends BaseOAuthProvider {
361361
// @public
362362
export const FactorId: {
363363
readonly PHONE: "phone";
364+
readonly TOTP: "totp";
364365
};
365366

366367
// @public
@@ -745,6 +746,41 @@ export function signInWithRedirect(auth: Auth, provider: AuthProvider, resolver?
745746
// @public
746747
export function signOut(auth: Auth): Promise<void>;
747748

749+
// @public
750+
export interface TotpMultiFactorAssertion extends MultiFactorAssertion {
751+
}
752+
753+
// @public
754+
export class TotpMultiFactorGenerator {
755+
static assertionForEnrollment(secret: TotpSecret, oneTimePassword: string): TotpMultiFactorAssertion;
756+
static assertionForSignIn(enrollmentId: string, oneTimePassword: string): TotpMultiFactorAssertion;
757+
// Warning: (ae-forgotten-export) The symbol "FactorId" needs to be exported by the entry point index.d.ts
758+
static FACTOR_ID: FactorId_2;
759+
static generateSecret(session: MultiFactorSession): Promise<TotpSecret>;
760+
}
761+
762+
// @public
763+
export interface TotpMultiFactorInfo extends MultiFactorInfo {
764+
}
765+
766+
// @public
767+
export class TotpSecret {
768+
readonly codeIntervalSeconds: number;
769+
readonly codeLength: number;
770+
readonly enrollmentCompletionDeadline: string;
771+
// Warning: (ae-forgotten-export) The symbol "StartTotpMfaEnrollmentResponse" needs to be exported by the entry point index.d.ts
772+
//
773+
// @internal (undocumented)
774+
static _fromStartTotpMfaEnrollmentResponse(response: StartTotpMfaEnrollmentResponse, auth: AuthInternal): TotpSecret;
775+
generateQrCodeUrl(accountName?: string, issuer?: string): string;
776+
readonly hashingAlgorithm: string;
777+
// Warning: (ae-forgotten-export) The symbol "TotpVerificationInfo" needs to be exported by the entry point index.d.ts
778+
//
779+
// @internal (undocumented)
780+
_makeTotpVerificationInfo(otp: string): TotpVerificationInfo;
781+
readonly secretKey: string;
782+
}
783+
748784
// @public
749785
export class TwitterAuthProvider extends BaseOAuthProvider {
750786
constructor();

docs-devsite/auth.md

+5
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ Firebase Authentication
9393
| [PhoneMultiFactorGenerator](./auth.phonemultifactorgenerator.md#phonemultifactorgenerator_class) | Provider for generating a [PhoneMultiFactorAssertion](./auth.phonemultifactorassertion.md#phonemultifactorassertion_interface)<!-- -->. |
9494
| [RecaptchaVerifier](./auth.recaptchaverifier.md#recaptchaverifier_class) | An [reCAPTCHA](https://www.google.com/recaptcha/)<!-- -->-based application verifier. |
9595
| [SAMLAuthProvider](./auth.samlauthprovider.md#samlauthprovider_class) | An [AuthProvider](./auth.authprovider.md#authprovider_interface) for SAML. |
96+
| [TotpMultiFactorGenerator](./auth.totpmultifactorgenerator.md#totpmultifactorgenerator_class) | Provider for generating a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface)<!-- -->. |
97+
| [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. |
9698
| [TwitterAuthProvider](./auth.twitterauthprovider.md#twitterauthprovider_class) | Provider for generating an [OAuthCredential](./auth.oauthcredential.md#oauthcredential_class) for [ProviderId](./auth.md#providerid)<!-- -->.TWITTER. |
9799

98100
## Interfaces
@@ -130,6 +132,8 @@ Firebase Authentication
130132
| [PopupRedirectResolver](./auth.popupredirectresolver.md#popupredirectresolver_interface) | A resolver used for handling DOM specific operations like [signInWithPopup()](./auth.md#signinwithpopup) or [signInWithRedirect()](./auth.md#signinwithredirect)<!-- -->. |
131133
| [ReactNativeAsyncStorage](./auth.reactnativeasyncstorage.md#reactnativeasyncstorage_interface) | Interface for a supplied <code>AsyncStorage</code>. |
132134
| [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 <code>sitekey</code>: Firebase Auth provisions a reCAPTCHA for each project and will configure the site key upon rendering.<!-- -->For an invisible reCAPTCHA, set the <code>size</code> key to <code>invisible</code>. |
135+
| [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)<!-- -->. |
136+
| [TotpMultiFactorInfo](./auth.totpmultifactorinfo.md#totpmultifactorinfo_interface) | The subclass of the [MultiFactorInfo](./auth.multifactorinfo.md#multifactorinfo_interface) interface for TOTP second factors. The <code>factorId</code> of this second factor is [FactorId](./auth.md#factorid)<!-- -->.TOTP. |
133137
| [User](./auth.user.md#user_interface) | A user account. |
134138
| [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. |
135139
| [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.
18551859
```typescript
18561860
FactorId: {
18571861
readonly PHONE: "phone";
1862+
readonly TOTP: "totp";
18581863
}
18591864
```
18601865

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Project: /docs/reference/js/_project.yaml
2+
Book: /docs/reference/_book.yaml
3+
page_type: reference
4+
5+
{% comment %}
6+
DO NOT EDIT THIS FILE!
7+
This is generated by the JS SDK team, and any local changes will be
8+
overwritten. Changes should be made in the source code at
9+
https://github.com/firebase/firebase-js-sdk
10+
{% endcomment %}
11+
12+
# TotpMultiFactorAssertion interface
13+
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)<!-- -->.
14+
15+
<b>Signature:</b>
16+
17+
```typescript
18+
export interface TotpMultiFactorAssertion extends MultiFactorAssertion
19+
```
20+
<b>Extends:</b> [MultiFactorAssertion](./auth.multifactorassertion.md#multifactorassertion_interface)
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
Project: /docs/reference/js/_project.yaml
2+
Book: /docs/reference/_book.yaml
3+
page_type: reference
4+
5+
{% comment %}
6+
DO NOT EDIT THIS FILE!
7+
This is generated by the JS SDK team, and any local changes will be
8+
overwritten. Changes should be made in the source code at
9+
https://github.com/firebase/firebase-js-sdk
10+
{% endcomment %}
11+
12+
# TotpMultiFactorGenerator class
13+
Provider for generating a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface)<!-- -->.
14+
15+
<b>Signature:</b>
16+
17+
```typescript
18+
export declare class TotpMultiFactorGenerator
19+
```
20+
21+
## Properties
22+
23+
| Property | Modifiers | Type | Description |
24+
| --- | --- | --- | --- |
25+
| [FACTOR\_ID](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorfactor_id) | <code>static</code> | FactorId | The identifier of the TOTP second factor: <code>totp</code>. |
26+
27+
## Methods
28+
29+
| Method | Modifiers | Description |
30+
| --- | --- | --- |
31+
| [assertionForEnrollment(secret, oneTimePassword)](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforenrollment) | <code>static</code> | 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. |
32+
| [assertionForSignIn(enrollmentId, oneTimePassword)](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorassertionforsignin) | <code>static</code> | 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. |
33+
| [generateSecret(session)](./auth.totpmultifactorgenerator.md#totpmultifactorgeneratorgeneratesecret) | <code>static</code> | 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. |
34+
35+
## TotpMultiFactorGenerator.FACTOR\_ID
36+
37+
The identifier of the TOTP second factor: `totp`<!-- -->.
38+
39+
<b>Signature:</b>
40+
41+
```typescript
42+
static FACTOR_ID: FactorId;
43+
```
44+
45+
## TotpMultiFactorGenerator.assertionForEnrollment()
46+
47+
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.
48+
49+
<b>Signature:</b>
50+
51+
```typescript
52+
static assertionForEnrollment(secret: TotpSecret, oneTimePassword: string): TotpMultiFactorAssertion;
53+
```
54+
55+
### Parameters
56+
57+
| Parameter | Type | Description |
58+
| --- | --- | --- |
59+
| secret | [TotpSecret](./auth.totpsecret.md#totpsecret_class) | A [TotpSecret](./auth.totpsecret.md#totpsecret_class) containing the shared secret key and other TOTP parameters. |
60+
| oneTimePassword | string | One-time password from TOTP App. |
61+
62+
<b>Returns:</b>
63+
64+
[TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface)
65+
66+
A [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) which can be used with [MultiFactorUser.enroll()](./auth.multifactoruser.md#multifactoruserenroll)<!-- -->.
67+
68+
## TotpMultiFactorGenerator.assertionForSignIn()
69+
70+
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.
71+
72+
<b>Signature:</b>
73+
74+
```typescript
75+
static assertionForSignIn(enrollmentId: string, oneTimePassword: string): TotpMultiFactorAssertion;
76+
```
77+
78+
### Parameters
79+
80+
| Parameter | Type | Description |
81+
| --- | --- | --- |
82+
| enrollmentId | string | identifies the enrolled TOTP second factor. |
83+
| oneTimePassword | string | One-time password from TOTP App. |
84+
85+
<b>Returns:</b>
86+
87+
[TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface)
88+
89+
A [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface) which can be used with [MultiFactorResolver.resolveSignIn()](./auth.multifactorresolver.md#multifactorresolverresolvesignin)<!-- -->.
90+
91+
## TotpMultiFactorGenerator.generateSecret()
92+
93+
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.
94+
95+
<b>Signature:</b>
96+
97+
```typescript
98+
static generateSecret(session: MultiFactorSession): Promise<TotpSecret>;
99+
```
100+
101+
### Parameters
102+
103+
| Parameter | Type | Description |
104+
| --- | --- | --- |
105+
| session | [MultiFactorSession](./auth.multifactorsession.md#multifactorsession_interface) | The [MultiFactorSession](./auth.multifactorsession.md#multifactorsession_interface) that the user is part of. |
106+
107+
<b>Returns:</b>
108+
109+
Promise&lt;[TotpSecret](./auth.totpsecret.md#totpsecret_class)<!-- -->&gt;
110+
111+
A promise to [TotpSecret](./auth.totpsecret.md#totpsecret_class)<!-- -->.
112+
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Project: /docs/reference/js/_project.yaml
2+
Book: /docs/reference/_book.yaml
3+
page_type: reference
4+
5+
{% comment %}
6+
DO NOT EDIT THIS FILE!
7+
This is generated by the JS SDK team, and any local changes will be
8+
overwritten. Changes should be made in the source code at
9+
https://github.com/firebase/firebase-js-sdk
10+
{% endcomment %}
11+
12+
# TotpMultiFactorInfo interface
13+
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.
14+
15+
<b>Signature:</b>
16+
17+
```typescript
18+
export interface TotpMultiFactorInfo extends MultiFactorInfo
19+
```
20+
<b>Extends:</b> [MultiFactorInfo](./auth.multifactorinfo.md#multifactorinfo_interface)
21+

docs-devsite/auth.totpsecret.md

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
Project: /docs/reference/js/_project.yaml
2+
Book: /docs/reference/_book.yaml
3+
page_type: reference
4+
5+
{% comment %}
6+
DO NOT EDIT THIS FILE!
7+
This is generated by the JS SDK team, and any local changes will be
8+
overwritten. Changes should be made in the source code at
9+
https://github.com/firebase/firebase-js-sdk
10+
{% endcomment %}
11+
12+
# TotpSecret class
13+
Provider for generating a [TotpMultiFactorAssertion](./auth.totpmultifactorassertion.md#totpmultifactorassertion_interface)<!-- -->.
14+
15+
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.
16+
17+
<b>Signature:</b>
18+
19+
```typescript
20+
export declare class TotpSecret
21+
```
22+
23+
## Properties
24+
25+
| Property | Modifiers | Type | Description |
26+
| --- | --- | --- | --- |
27+
| [codeIntervalSeconds](./auth.totpsecret.md#totpsecretcodeintervalseconds) | | number | The interval (in seconds) when the OTP codes should change. |
28+
| [codeLength](./auth.totpsecret.md#totpsecretcodelength) | | number | Length of the one-time passwords to be generated. |
29+
| [enrollmentCompletionDeadline](./auth.totpsecret.md#totpsecretenrollmentcompletiondeadline) | | string | The timestamp (UTC string) by which TOTP enrollment should be completed. |
30+
| [hashingAlgorithm](./auth.totpsecret.md#totpsecrethashingalgorithm) | | string | Hashing algorithm used. |
31+
| [secretKey](./auth.totpsecret.md#totpsecretsecretkey) | | string | Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs. |
32+
33+
## Methods
34+
35+
| Method | Modifiers | Description |
36+
| --- | --- | --- |
37+
| [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 <userEmail> and issuer of <firebaseAppName> are used. |
38+
39+
## TotpSecret.codeIntervalSeconds
40+
41+
The interval (in seconds) when the OTP codes should change.
42+
43+
<b>Signature:</b>
44+
45+
```typescript
46+
readonly codeIntervalSeconds: number;
47+
```
48+
49+
## TotpSecret.codeLength
50+
51+
Length of the one-time passwords to be generated.
52+
53+
<b>Signature:</b>
54+
55+
```typescript
56+
readonly codeLength: number;
57+
```
58+
59+
## TotpSecret.enrollmentCompletionDeadline
60+
61+
The timestamp (UTC string) by which TOTP enrollment should be completed.
62+
63+
<b>Signature:</b>
64+
65+
```typescript
66+
readonly enrollmentCompletionDeadline: string;
67+
```
68+
69+
## TotpSecret.hashingAlgorithm
70+
71+
Hashing algorithm used.
72+
73+
<b>Signature:</b>
74+
75+
```typescript
76+
readonly hashingAlgorithm: string;
77+
```
78+
79+
## TotpSecret.secretKey
80+
81+
Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs.
82+
83+
<b>Signature:</b>
84+
85+
```typescript
86+
readonly secretKey: string;
87+
```
88+
89+
## TotpSecret.generateQrCodeUrl()
90+
91+
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 <userEmail> and issuer of <firebaseAppName> are used.
92+
93+
<b>Signature:</b>
94+
95+
```typescript
96+
generateQrCodeUrl(accountName?: string, issuer?: string): string;
97+
```
98+
99+
### Parameters
100+
101+
| Parameter | Type | Description |
102+
| --- | --- | --- |
103+
| accountName | string | the name of the account/app along with a user identifier. |
104+
| issuer | string | issuer of the TOTP (likely the app name). |
105+
106+
<b>Returns:</b>
107+
108+
string
109+
110+
A QR code URL string.
111+

packages/auth/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ host of npm scripts to run these tests. The most important commands are:
1717
| `yarn test:<platform>:unit:debug` | Runs \<platform> unit tests, auto-watching for file system changes |
1818
| `yarn test:<platform>:integration` | Runs only integration tests against the live environment |
1919
| `yarn test:<platform>:integration:local` | Runs all headless \<platform> integration tests against the emulator (more below) |
20+
| `yarn test:browser:integration:prodbackend` | Runs TOTP MFA integration tests against the backend (more below) |
2021

2122
Where \<platform> is "browser" or "node". There are also cordova tests, but they
2223
are not broken into such granular details. Check out `package.json` for more.
@@ -46,6 +47,25 @@ you would simply execute the following command:
4647
firebase emulators:exec --project foo-bar --only auth "yarn test:integration:local"
4748
```
4849

50+
### Integration testing with the production backend
51+
52+
Currently, MFA TOTP tests only run against the production backend (since they are not supported on the emulator yet).
53+
Running against the backend also makes it a more reliable end-to-end test.
54+
55+
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:
56+
57+
'[email protected]', 'password'
58+
59+
You also need to verify this email address, in order to use MFA. This can be done with a curl command like this:
60+
61+
```
62+
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 '{
63+
"email": "[email protected]",
64+
"requestType": "VERIFY_EMAIL",
65+
"returnOobLink": true,
66+
}'
67+
```
68+
4969
### Selenium Webdriver tests
5070

5171
These tests assume that you have both Firefox and Chrome installed on your

0 commit comments

Comments
 (0)