@metamask-previews/profile-sync-controller 32.1.1-preview-d3f9964be → 32.2.0-preview-aecbce4ff
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.
- package/CHANGELOG.md +16 -1
- package/README.md +21 -0
- package/dist/controllers/authentication/AuthenticationController-method-action-types.d.ts +43 -1
- package/dist/controllers/authentication/AuthenticationController-method-action-types.d.ts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController-method-action-types.js.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.d.ts +42 -1
- package/dist/controllers/authentication/AuthenticationController.d.ts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.js +167 -10
- package/dist/controllers/authentication/AuthenticationController.js.map +1 -1
- package/dist/controllers/authentication/index.d.ts +1 -1
- package/dist/controllers/authentication/index.d.ts.map +1 -1
- package/dist/controllers/authentication/index.js.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.d.ts +3 -0
- package/dist/sdk/authentication-jwt-bearer/flow-srp.d.ts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.js +3 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.js.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/mfa/schemas.d.ts +2 -0
- package/dist/sdk/authentication-jwt-bearer/mfa/schemas.d.ts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/mfa/schemas.js +1 -0
- package/dist/sdk/authentication-jwt-bearer/mfa/schemas.js.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/mfa/services.d.ts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/mfa/services.js +16 -11
- package/dist/sdk/authentication-jwt-bearer/mfa/services.js.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/mfa/types.d.ts +1 -1
- package/dist/sdk/authentication-jwt-bearer/mfa/types.d.ts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/mfa/types.js.map +1 -1
- package/dist/sdk/authentication.d.ts +1 -0
- package/dist/sdk/authentication.d.ts.map +1 -1
- package/dist/sdk/authentication.js.map +1 -1
- package/dist/sdk/constants.d.ts +1 -0
- package/dist/sdk/constants.d.ts.map +1 -1
- package/dist/sdk/constants.js +1 -0
- package/dist/sdk/constants.js.map +1 -1
- package/dist/sdk/errors.d.ts +16 -1
- package/dist/sdk/errors.d.ts.map +1 -1
- package/dist/sdk/errors.js +18 -0
- package/dist/sdk/errors.js.map +1 -1
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- Support AAL2-gated MFA enrollment and sync the MFA SDK with the latest authentication API spec ([#10374](https://github.com/MetaMask/core/pull/10374))
|
|
13
|
+
- `beginMfaEnrollment` accepts an `accessToken` option so enrollment can begin with an elevated token
|
|
14
|
+
- `AuthenticationController.beginCredentialEnrollment` sends the elevated token while a step-up session is live, since enrolling additional credentials requires AAL2
|
|
15
|
+
- Add the `email_socially_verified`, `multi_primary_srp` and `aal2_required` MFA error codes, a `StepUpRequiredError` class, and support for the `retry_after_seconds` error field when computing `retryAfterMs`
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Bump `immer` from `^9.0.6` to `^9.0.21` ([#10331](https://github.com/MetaMask/core/pull/10331))
|
|
20
|
+
|
|
21
|
+
## [32.2.0]
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Add `beginStepUp`, `completeStepUp`, `getElevatedProfileToken` and `clearStepUpSession` to `AuthenticationController`, holding the elevated token in memory only behind a hard-expiring `stepUpSessionExpiresAt` state ([#10267](https://github.com/MetaMask/core/pull/10267))
|
|
12
26
|
- Add `refreshEnrolledCredentials`, `beginCredentialEnrollment` and `completeCredentialEnrollment` to `AuthenticationController`, backed by a memory-only `enrolledCredentials` state and an optional `trace` callback ([#10266](https://github.com/MetaMask/core/pull/10266))
|
|
13
27
|
- Add passkey and email OTP enrollment, verification, credential-list, and elevated-token exchange SDK methods ([#10265](https://github.com/MetaMask/core/pull/10265))
|
|
14
28
|
- Add validated MFA domain types and structured `MfaError` classes with a serialization-safe `mfaCode` ([#10264](https://github.com/MetaMask/core/pull/10264))
|
|
@@ -977,7 +991,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
977
991
|
|
|
978
992
|
- Initial release
|
|
979
993
|
|
|
980
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/profile-sync-controller@32.
|
|
994
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/profile-sync-controller@32.2.0...HEAD
|
|
995
|
+
[32.2.0]: https://github.com/MetaMask/core/compare/@metamask/profile-sync-controller@32.1.1...@metamask/profile-sync-controller@32.2.0
|
|
981
996
|
[32.1.1]: https://github.com/MetaMask/core/compare/@metamask/profile-sync-controller@32.1.0...@metamask/profile-sync-controller@32.1.1
|
|
982
997
|
[32.1.0]: https://github.com/MetaMask/core/compare/@metamask/profile-sync-controller@32.0.0...@metamask/profile-sync-controller@32.1.0
|
|
983
998
|
[32.0.0]: https://github.com/MetaMask/core/compare/@metamask/profile-sync-controller@31.0.0...@metamask/profile-sync-controller@32.0.0
|
package/README.md
CHANGED
|
@@ -42,6 +42,27 @@ import { ... } from '@metamask/profile-sync-controller/auth/mocks'
|
|
|
42
42
|
import { ... } from '@metamask/profile-sync-controller/user-storage/mocks'
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
## Multi-factor authentication
|
|
46
|
+
|
|
47
|
+
`AuthenticationController` exposes UI-independent primitives for passkey and
|
|
48
|
+
email OTP enrollment and step-up verification:
|
|
49
|
+
|
|
50
|
+
- `refreshEnrolledCredentials()` refreshes the in-memory credential list.
|
|
51
|
+
- `beginCredentialEnrollment()` and `completeCredentialEnrollment()` surround
|
|
52
|
+
a client-owned passkey ceremony or email-code screen. Beginning enrollment
|
|
53
|
+
of a second or later credential requires an elevated session:
|
|
54
|
+
`beginCredentialEnrollment()` sends the elevated token while one is live,
|
|
55
|
+
and the server otherwise rejects it with `aal2_required`, so clients should
|
|
56
|
+
step up and retry.
|
|
57
|
+
- `beginStepUp()` and `completeStepUp()` verify an enrolled credential and
|
|
58
|
+
return an elevated profile token.
|
|
59
|
+
- `getElevatedProfileToken()` reuses a live elevated session when it satisfies
|
|
60
|
+
the caller's freshness requirement; `clearStepUpSession()` clears it.
|
|
61
|
+
|
|
62
|
+
Clients must retain the challenge `flowId`, perform the platform ceremony, and
|
|
63
|
+
send the resulting proof to the matching completion method. OTP codes,
|
|
64
|
+
passkey results, and elevated tokens are never persisted in controller state.
|
|
65
|
+
|
|
45
66
|
## Contributing
|
|
46
67
|
|
|
47
68
|
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
|
@@ -53,6 +53,48 @@ export type AuthenticationControllerCompleteCredentialEnrollmentAction = {
|
|
|
53
53
|
type: `AuthenticationController:completeCredentialEnrollment`;
|
|
54
54
|
handler: AuthenticationController['completeCredentialEnrollment'];
|
|
55
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* Begins step-up verification with an enrolled credential.
|
|
58
|
+
*
|
|
59
|
+
* @param request - Credential type and trace reason.
|
|
60
|
+
* @returns A challenge for the client-owned ceremony.
|
|
61
|
+
*/
|
|
62
|
+
export type AuthenticationControllerBeginStepUpAction = {
|
|
63
|
+
type: `AuthenticationController:beginStepUp`;
|
|
64
|
+
handler: AuthenticationController['beginStepUp'];
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Completes step-up verification and opens a short-lived elevated session.
|
|
68
|
+
*
|
|
69
|
+
* The AAL2 assertion returned by the MFA service is exchanged at Hydra for
|
|
70
|
+
* an elevated access token, whose claims are checked before the session
|
|
71
|
+
* opens. The token itself never enters controller state.
|
|
72
|
+
*
|
|
73
|
+
* @param request - Flow identifier, platform or email proof, and trace reason.
|
|
74
|
+
* @returns The elevated profile access token.
|
|
75
|
+
*/
|
|
76
|
+
export type AuthenticationControllerCompleteStepUpAction = {
|
|
77
|
+
type: `AuthenticationController:completeStepUp`;
|
|
78
|
+
handler: AuthenticationController['completeStepUp'];
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Returns the active elevated token when it meets the requested freshness.
|
|
82
|
+
*
|
|
83
|
+
* @param request - Optional maximum session age in milliseconds, measured
|
|
84
|
+
* from when the token was obtained. Zero always requires a new ceremony.
|
|
85
|
+
* @returns A live elevated token, or null when no reusable session exists.
|
|
86
|
+
*/
|
|
87
|
+
export type AuthenticationControllerGetElevatedProfileTokenAction = {
|
|
88
|
+
type: `AuthenticationController:getElevatedProfileToken`;
|
|
89
|
+
handler: AuthenticationController['getElevatedProfileToken'];
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Clears the in-memory elevated session and its expiration timer.
|
|
93
|
+
*/
|
|
94
|
+
export type AuthenticationControllerClearStepUpSessionAction = {
|
|
95
|
+
type: `AuthenticationController:clearStepUpSession`;
|
|
96
|
+
handler: AuthenticationController['clearStepUpSession'];
|
|
97
|
+
};
|
|
56
98
|
export type AuthenticationControllerPerformSignOutAction = {
|
|
57
99
|
type: `AuthenticationController:performSignOut`;
|
|
58
100
|
handler: AuthenticationController['performSignOut'];
|
|
@@ -160,5 +202,5 @@ export type AuthenticationControllerIsSignedInAction = {
|
|
|
160
202
|
/**
|
|
161
203
|
* Union of all AuthenticationController action types.
|
|
162
204
|
*/
|
|
163
|
-
export type AuthenticationControllerMethodActions = AuthenticationControllerPerformSignInAction | AuthenticationControllerRequestProfilePairingAction | AuthenticationControllerRefreshEnrolledCredentialsAction | AuthenticationControllerBeginCredentialEnrollmentAction | AuthenticationControllerCompleteCredentialEnrollmentAction | AuthenticationControllerPerformSignOutAction | AuthenticationControllerClearStateAction | AuthenticationControllerGetBearerTokenAction | AuthenticationControllerGetSessionProfileAction | AuthenticationControllerRefreshCanonicalProfileIdAction | AuthenticationControllerGetUserProfileLineageAction | AuthenticationControllerGetCustomerServiceTokenAction | AuthenticationControllerGetPartnerIdentityTokenAction | AuthenticationControllerIsSignedInAction;
|
|
205
|
+
export type AuthenticationControllerMethodActions = AuthenticationControllerPerformSignInAction | AuthenticationControllerRequestProfilePairingAction | AuthenticationControllerRefreshEnrolledCredentialsAction | AuthenticationControllerBeginCredentialEnrollmentAction | AuthenticationControllerCompleteCredentialEnrollmentAction | AuthenticationControllerBeginStepUpAction | AuthenticationControllerCompleteStepUpAction | AuthenticationControllerGetElevatedProfileTokenAction | AuthenticationControllerClearStepUpSessionAction | AuthenticationControllerPerformSignOutAction | AuthenticationControllerClearStateAction | AuthenticationControllerGetBearerTokenAction | AuthenticationControllerGetSessionProfileAction | AuthenticationControllerRefreshCanonicalProfileIdAction | AuthenticationControllerGetUserProfileLineageAction | AuthenticationControllerGetCustomerServiceTokenAction | AuthenticationControllerGetPartnerIdentityTokenAction | AuthenticationControllerIsSignedInAction;
|
|
164
206
|
//# sourceMappingURL=AuthenticationController-method-action-types.d.ts.map
|
package/dist/controllers/authentication/AuthenticationController-method-action-types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationController-method-action-types.d.ts","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController-method-action-types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuthenticationController-method-action-types.d.ts","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController-method-action-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationController-method-action-types.js","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AuthenticationController } from './AuthenticationController.js';\n\nexport type AuthenticationControllerPerformSignInAction = {\n type: `AuthenticationController:performSignIn`;\n handler: AuthenticationController['performSignIn'];\n};\n\n/**\n * Marks profile pairing as needed. Clients call this when the SRP set\n * changes (e.g. a new keyring was added) so the next auto-sign-in cycle\n * re-runs `performSignIn` and re-pairs.\n */\nexport type AuthenticationControllerRequestProfilePairingAction = {\n type: `AuthenticationController:requestProfilePairing`;\n handler: AuthenticationController['requestProfilePairing'];\n};\n\n/**\n * Refreshes credentials enrolled on the canonical profile.\n *\n * @returns The current supported credentials.\n */\nexport type AuthenticationControllerRefreshEnrolledCredentialsAction = {\n type: `AuthenticationController:refreshEnrolledCredentials`;\n handler: AuthenticationController['refreshEnrolledCredentials'];\n};\n\n/**\n * Begins enrollment of a passkey or email OTP credential.\n *\n * @param request - Credential, optional email address, and trace reason.\n * @returns A challenge for the client-owned ceremony.\n */\nexport type AuthenticationControllerBeginCredentialEnrollmentAction = {\n type: `AuthenticationController:beginCredentialEnrollment`;\n handler: AuthenticationController['beginCredentialEnrollment'];\n};\n\n/**\n * Completes credential enrollment and refreshes the credential cache.\n *\n * A cache-refresh failure does not undo successful enrollment. Email\n * enrollment invalidates the primary SRP session *after* refresh so the\n * credentials call can reuse the still-valid access token; the next token\n * fetch then includes the newly verified email claim. That invalidation\n * happens even if the session ends mid-request: the enrollment succeeded\n * on the server, so a token cached across a lock must not be reused\n * without the new claim.\n *\n * @param request - Flow identifier, platform or email proof, and trace reason.\n * @returns The refreshed credentials, or the existing cache if refresh fails.\n */\nexport type AuthenticationControllerCompleteCredentialEnrollmentAction = {\n type: `AuthenticationController:completeCredentialEnrollment`;\n handler: AuthenticationController['completeCredentialEnrollment'];\n};\n\nexport type AuthenticationControllerPerformSignOutAction = {\n type: `AuthenticationController:performSignOut`;\n handler: AuthenticationController['performSignOut'];\n};\n\n/**\n * Resets the controller to `defaultState`. Clients call this on wallet reset\n * so the next wallet starts unsigned with both pairing gates re-armed.\n */\nexport type AuthenticationControllerClearStateAction = {\n type: `AuthenticationController:clearState`;\n handler: AuthenticationController['clearState'];\n};\n\n/**\n * Returns a bearer token for the specified SRP, logging in if needed.\n *\n * When called without `entropySourceId`, returns the primary (first) SRP's\n * access token, which is effectively the canonical\n * profile's token that can be used by alias-aware consumers for cross-SRP\n * operations.\n *\n * @param entropySourceId - The entropy source ID. Omit for the primary SRP.\n * @returns The OIDC access token.\n */\nexport type AuthenticationControllerGetBearerTokenAction = {\n type: `AuthenticationController:getBearerToken`;\n handler: AuthenticationController['getBearerToken'];\n};\n\n/**\n * Returns the cached session profile, logging in if no session exists.\n *\n * The returned `canonicalProfileId` reflects the value from the most recent\n * login or pairing. In the rare event where a canonical changed because of\n * a pairing that happened on another device, the cached value may be stale\n * until the next login. For guaranteed freshness, call\n * `refreshCanonicalProfileId()` before reading `canonicalProfileId`.\n *\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns profile for the session.\n */\nexport type AuthenticationControllerGetSessionProfileAction = {\n type: `AuthenticationController:getSessionProfile`;\n handler: AuthenticationController['getSessionProfile'];\n};\n\n/**\n * Forces a fresh retrieval of the canonical profile ID from the server\n * and propagates it to all cached SRP sessions.\n *\n * This method invalidates the primary SRP's cached session and forces a\n * re-login. Use it before operations that require a guaranteed-fresh\n * canonical (e.g. storage key derivation for Accounts ADR 0005). For\n * best-effort reads, use\n * `getSessionProfile().canonicalProfileId` instead.\n *\n * Only the primary SRP is re-logged-in regardless of how many SRPs exist —\n * the server returns the current canonical for the entire pairing group\n * from any single SRP login.\n *\n * @returns The refreshed canonical profile ID.\n */\nexport type AuthenticationControllerRefreshCanonicalProfileIdAction = {\n type: `AuthenticationController:refreshCanonicalProfileId`;\n handler: AuthenticationController['refreshCanonicalProfileId'];\n};\n\nexport type AuthenticationControllerGetUserProfileLineageAction = {\n type: `AuthenticationController:getUserProfileLineage`;\n handler: AuthenticationController['getUserProfileLineage'];\n};\n\n/**\n * Returns a Customer Service specific access token for the specified SRP,\n * logging in if needed.\n *\n * Exchanges the OIDC access token for a short-lived token scoped to the\n * customer-service audience. Customer Service tooling consumes this token to\n * identify and authenticate the user.\n *\n * @param entropySourceId - The entropy source ID. Omit for the primary SRP.\n * @returns The customer-service access token.\n */\nexport type AuthenticationControllerGetCustomerServiceTokenAction = {\n type: `AuthenticationController:getCustomerServiceToken`;\n handler: AuthenticationController['getCustomerServiceToken'];\n};\n\n/**\n * Mints a partner identity token for the specified SRP, logging in if needed.\n *\n * Calls `POST /api/v2/oidc/token` with the Hydra login bearer and returns\n * the minted `access_token`. Email on live tokens is under JWT `ext`.\n * HTTP 422 throws `EmailRequiredError` when this profile has no\n * verified email.\n *\n * @param claims - Claim names to embed. Only `email` is supported.\n * @param audience - Partner audience (`kyc` or `iron`).\n * @param entropySourceId - The entropy source ID. Omit for the primary SRP.\n * @returns The partner identity access token.\n */\nexport type AuthenticationControllerGetPartnerIdentityTokenAction = {\n type: `AuthenticationController:getPartnerIdentityToken`;\n handler: AuthenticationController['getPartnerIdentityToken'];\n};\n\nexport type AuthenticationControllerIsSignedInAction = {\n type: `AuthenticationController:isSignedIn`;\n handler: AuthenticationController['isSignedIn'];\n};\n\n/**\n * Union of all AuthenticationController action types.\n */\nexport type AuthenticationControllerMethodActions =\n | AuthenticationControllerPerformSignInAction\n | AuthenticationControllerRequestProfilePairingAction\n | AuthenticationControllerRefreshEnrolledCredentialsAction\n | AuthenticationControllerBeginCredentialEnrollmentAction\n | AuthenticationControllerCompleteCredentialEnrollmentAction\n | AuthenticationControllerPerformSignOutAction\n | AuthenticationControllerClearStateAction\n | AuthenticationControllerGetBearerTokenAction\n | AuthenticationControllerGetSessionProfileAction\n | AuthenticationControllerRefreshCanonicalProfileIdAction\n | AuthenticationControllerGetUserProfileLineageAction\n | AuthenticationControllerGetCustomerServiceTokenAction\n | AuthenticationControllerGetPartnerIdentityTokenAction\n | AuthenticationControllerIsSignedInAction;\n"]}
|
|
1
|
+
{"version":3,"file":"AuthenticationController-method-action-types.js","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AuthenticationController } from './AuthenticationController.js';\n\nexport type AuthenticationControllerPerformSignInAction = {\n type: `AuthenticationController:performSignIn`;\n handler: AuthenticationController['performSignIn'];\n};\n\n/**\n * Marks profile pairing as needed. Clients call this when the SRP set\n * changes (e.g. a new keyring was added) so the next auto-sign-in cycle\n * re-runs `performSignIn` and re-pairs.\n */\nexport type AuthenticationControllerRequestProfilePairingAction = {\n type: `AuthenticationController:requestProfilePairing`;\n handler: AuthenticationController['requestProfilePairing'];\n};\n\n/**\n * Refreshes credentials enrolled on the canonical profile.\n *\n * @returns The current supported credentials.\n */\nexport type AuthenticationControllerRefreshEnrolledCredentialsAction = {\n type: `AuthenticationController:refreshEnrolledCredentials`;\n handler: AuthenticationController['refreshEnrolledCredentials'];\n};\n\n/**\n * Begins enrollment of a passkey or email OTP credential.\n *\n * @param request - Credential, optional email address, and trace reason.\n * @returns A challenge for the client-owned ceremony.\n */\nexport type AuthenticationControllerBeginCredentialEnrollmentAction = {\n type: `AuthenticationController:beginCredentialEnrollment`;\n handler: AuthenticationController['beginCredentialEnrollment'];\n};\n\n/**\n * Completes credential enrollment and refreshes the credential cache.\n *\n * A cache-refresh failure does not undo successful enrollment. Email\n * enrollment invalidates the primary SRP session *after* refresh so the\n * credentials call can reuse the still-valid access token; the next token\n * fetch then includes the newly verified email claim. That invalidation\n * happens even if the session ends mid-request: the enrollment succeeded\n * on the server, so a token cached across a lock must not be reused\n * without the new claim.\n *\n * @param request - Flow identifier, platform or email proof, and trace reason.\n * @returns The refreshed credentials, or the existing cache if refresh fails.\n */\nexport type AuthenticationControllerCompleteCredentialEnrollmentAction = {\n type: `AuthenticationController:completeCredentialEnrollment`;\n handler: AuthenticationController['completeCredentialEnrollment'];\n};\n\n/**\n * Begins step-up verification with an enrolled credential.\n *\n * @param request - Credential type and trace reason.\n * @returns A challenge for the client-owned ceremony.\n */\nexport type AuthenticationControllerBeginStepUpAction = {\n type: `AuthenticationController:beginStepUp`;\n handler: AuthenticationController['beginStepUp'];\n};\n\n/**\n * Completes step-up verification and opens a short-lived elevated session.\n *\n * The AAL2 assertion returned by the MFA service is exchanged at Hydra for\n * an elevated access token, whose claims are checked before the session\n * opens. The token itself never enters controller state.\n *\n * @param request - Flow identifier, platform or email proof, and trace reason.\n * @returns The elevated profile access token.\n */\nexport type AuthenticationControllerCompleteStepUpAction = {\n type: `AuthenticationController:completeStepUp`;\n handler: AuthenticationController['completeStepUp'];\n};\n\n/**\n * Returns the active elevated token when it meets the requested freshness.\n *\n * @param request - Optional maximum session age in milliseconds, measured\n * from when the token was obtained. Zero always requires a new ceremony.\n * @returns A live elevated token, or null when no reusable session exists.\n */\nexport type AuthenticationControllerGetElevatedProfileTokenAction = {\n type: `AuthenticationController:getElevatedProfileToken`;\n handler: AuthenticationController['getElevatedProfileToken'];\n};\n\n/**\n * Clears the in-memory elevated session and its expiration timer.\n */\nexport type AuthenticationControllerClearStepUpSessionAction = {\n type: `AuthenticationController:clearStepUpSession`;\n handler: AuthenticationController['clearStepUpSession'];\n};\n\nexport type AuthenticationControllerPerformSignOutAction = {\n type: `AuthenticationController:performSignOut`;\n handler: AuthenticationController['performSignOut'];\n};\n\n/**\n * Resets the controller to `defaultState`. Clients call this on wallet reset\n * so the next wallet starts unsigned with both pairing gates re-armed.\n */\nexport type AuthenticationControllerClearStateAction = {\n type: `AuthenticationController:clearState`;\n handler: AuthenticationController['clearState'];\n};\n\n/**\n * Returns a bearer token for the specified SRP, logging in if needed.\n *\n * When called without `entropySourceId`, returns the primary (first) SRP's\n * access token, which is effectively the canonical\n * profile's token that can be used by alias-aware consumers for cross-SRP\n * operations.\n *\n * @param entropySourceId - The entropy source ID. Omit for the primary SRP.\n * @returns The OIDC access token.\n */\nexport type AuthenticationControllerGetBearerTokenAction = {\n type: `AuthenticationController:getBearerToken`;\n handler: AuthenticationController['getBearerToken'];\n};\n\n/**\n * Returns the cached session profile, logging in if no session exists.\n *\n * The returned `canonicalProfileId` reflects the value from the most recent\n * login or pairing. In the rare event where a canonical changed because of\n * a pairing that happened on another device, the cached value may be stale\n * until the next login. For guaranteed freshness, call\n * `refreshCanonicalProfileId()` before reading `canonicalProfileId`.\n *\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns profile for the session.\n */\nexport type AuthenticationControllerGetSessionProfileAction = {\n type: `AuthenticationController:getSessionProfile`;\n handler: AuthenticationController['getSessionProfile'];\n};\n\n/**\n * Forces a fresh retrieval of the canonical profile ID from the server\n * and propagates it to all cached SRP sessions.\n *\n * This method invalidates the primary SRP's cached session and forces a\n * re-login. Use it before operations that require a guaranteed-fresh\n * canonical (e.g. storage key derivation for Accounts ADR 0005). For\n * best-effort reads, use\n * `getSessionProfile().canonicalProfileId` instead.\n *\n * Only the primary SRP is re-logged-in regardless of how many SRPs exist —\n * the server returns the current canonical for the entire pairing group\n * from any single SRP login.\n *\n * @returns The refreshed canonical profile ID.\n */\nexport type AuthenticationControllerRefreshCanonicalProfileIdAction = {\n type: `AuthenticationController:refreshCanonicalProfileId`;\n handler: AuthenticationController['refreshCanonicalProfileId'];\n};\n\nexport type AuthenticationControllerGetUserProfileLineageAction = {\n type: `AuthenticationController:getUserProfileLineage`;\n handler: AuthenticationController['getUserProfileLineage'];\n};\n\n/**\n * Returns a Customer Service specific access token for the specified SRP,\n * logging in if needed.\n *\n * Exchanges the OIDC access token for a short-lived token scoped to the\n * customer-service audience. Customer Service tooling consumes this token to\n * identify and authenticate the user.\n *\n * @param entropySourceId - The entropy source ID. Omit for the primary SRP.\n * @returns The customer-service access token.\n */\nexport type AuthenticationControllerGetCustomerServiceTokenAction = {\n type: `AuthenticationController:getCustomerServiceToken`;\n handler: AuthenticationController['getCustomerServiceToken'];\n};\n\n/**\n * Mints a partner identity token for the specified SRP, logging in if needed.\n *\n * Calls `POST /api/v2/oidc/token` with the Hydra login bearer and returns\n * the minted `access_token`. Email on live tokens is under JWT `ext`.\n * HTTP 422 throws `EmailRequiredError` when this profile has no\n * verified email.\n *\n * @param claims - Claim names to embed. Only `email` is supported.\n * @param audience - Partner audience (`kyc` or `iron`).\n * @param entropySourceId - The entropy source ID. Omit for the primary SRP.\n * @returns The partner identity access token.\n */\nexport type AuthenticationControllerGetPartnerIdentityTokenAction = {\n type: `AuthenticationController:getPartnerIdentityToken`;\n handler: AuthenticationController['getPartnerIdentityToken'];\n};\n\nexport type AuthenticationControllerIsSignedInAction = {\n type: `AuthenticationController:isSignedIn`;\n handler: AuthenticationController['isSignedIn'];\n};\n\n/**\n * Union of all AuthenticationController action types.\n */\nexport type AuthenticationControllerMethodActions =\n | AuthenticationControllerPerformSignInAction\n | AuthenticationControllerRequestProfilePairingAction\n | AuthenticationControllerRefreshEnrolledCredentialsAction\n | AuthenticationControllerBeginCredentialEnrollmentAction\n | AuthenticationControllerCompleteCredentialEnrollmentAction\n | AuthenticationControllerBeginStepUpAction\n | AuthenticationControllerCompleteStepUpAction\n | AuthenticationControllerGetElevatedProfileTokenAction\n | AuthenticationControllerClearStepUpSessionAction\n | AuthenticationControllerPerformSignOutAction\n | AuthenticationControllerClearStateAction\n | AuthenticationControllerGetBearerTokenAction\n | AuthenticationControllerGetSessionProfileAction\n | AuthenticationControllerRefreshCanonicalProfileIdAction\n | AuthenticationControllerGetUserProfileLineageAction\n | AuthenticationControllerGetCustomerServiceTokenAction\n | AuthenticationControllerGetPartnerIdentityTokenAction\n | AuthenticationControllerIsSignedInAction;\n"]}
|
|
@@ -4,7 +4,7 @@ import type { TraceCallback } from '@metamask/controller-utils';
|
|
|
4
4
|
import type { KeyringControllerGetStateAction, KeyringControllerLockEvent, KeyringControllerUnlockEvent, KeyringControllerWithKeyringV2UnsafeAction } from '@metamask/keyring-controller';
|
|
5
5
|
import type { Messenger } from '@metamask/messenger';
|
|
6
6
|
import type { SeedlessOnboardingControllerGetAccessTokenAction, SeedlessOnboardingControllerGetStateAction } from '@metamask/seedless-onboarding-controller';
|
|
7
|
-
import type { LoginResponse, ProfileAlias, UserProfile, UserProfileLineage, OidcTokenAudience, OidcTokenClaims, BeginEnrollmentRequest, CompleteEnrollmentRequest, EnrolledCredential, EnrollmentChallenge } from '../../sdk/index.js';
|
|
7
|
+
import type { LoginResponse, ProfileAlias, UserProfile, UserProfileLineage, OidcTokenAudience, OidcTokenClaims, BeginEnrollmentRequest, CompleteEnrollmentRequest, EnrolledCredential, EnrollmentChallenge, BeginStepUpRequest, CompleteStepUpRequest, ElevatedProfileToken, GetElevatedTokenRequest, StepUpChallenge } from '../../sdk/index.js';
|
|
8
8
|
import { Env } from '../../sdk/index.js';
|
|
9
9
|
import type { MetaMetricsAuth } from '../../shared/types/services.js';
|
|
10
10
|
import { AuthenticationControllerMethodActions } from './AuthenticationController-method-action-types.js';
|
|
@@ -18,6 +18,11 @@ export type AuthenticationControllerState = {
|
|
|
18
18
|
* assignable to the controller state type.
|
|
19
19
|
*/
|
|
20
20
|
enrolledCredentials?: EnrolledCredential[];
|
|
21
|
+
/**
|
|
22
|
+
* Epoch-ms hard expiry of the in-memory elevated session, or undefined when
|
|
23
|
+
* none is open. Lets UI show "verified" state without holding the token.
|
|
24
|
+
*/
|
|
25
|
+
stepUpSessionExpiresAt?: number;
|
|
21
26
|
/**
|
|
22
27
|
* Client gate for profile pairing. Defaults to `true` (fresh install /
|
|
23
28
|
* upgrade), set to `false` after a successful `performSignIn` pair, set
|
|
@@ -45,6 +50,12 @@ export type AuthenticationControllerState = {
|
|
|
45
50
|
needsSocialPairing?: boolean;
|
|
46
51
|
};
|
|
47
52
|
export declare const defaultState: AuthenticationControllerState;
|
|
53
|
+
/**
|
|
54
|
+
* Lifetime of an elevated session. Deliberately shorter than the
|
|
55
|
+
* elevated token's own `exp` so a fresh ceremony is required per sensitive
|
|
56
|
+
* action window, per the MFA phase-1 specification.
|
|
57
|
+
*/
|
|
58
|
+
export declare const STEP_UP_SESSION_TTL_MS = 60000;
|
|
48
59
|
type ControllerConfig = {
|
|
49
60
|
env: Env;
|
|
50
61
|
/**
|
|
@@ -122,6 +133,36 @@ export declare class AuthenticationController extends BaseController<typeof cont
|
|
|
122
133
|
* @returns The refreshed credentials, or the existing cache if refresh fails.
|
|
123
134
|
*/
|
|
124
135
|
completeCredentialEnrollment(request: CompleteEnrollmentRequest): Promise<EnrolledCredential[]>;
|
|
136
|
+
/**
|
|
137
|
+
* Begins step-up verification with an enrolled credential.
|
|
138
|
+
*
|
|
139
|
+
* @param request - Credential type and trace reason.
|
|
140
|
+
* @returns A challenge for the client-owned ceremony.
|
|
141
|
+
*/
|
|
142
|
+
beginStepUp(request: BeginStepUpRequest): Promise<StepUpChallenge>;
|
|
143
|
+
/**
|
|
144
|
+
* Completes step-up verification and opens a short-lived elevated session.
|
|
145
|
+
*
|
|
146
|
+
* The AAL2 assertion returned by the MFA service is exchanged at Hydra for
|
|
147
|
+
* an elevated access token, whose claims are checked before the session
|
|
148
|
+
* opens. The token itself never enters controller state.
|
|
149
|
+
*
|
|
150
|
+
* @param request - Flow identifier, platform or email proof, and trace reason.
|
|
151
|
+
* @returns The elevated profile access token.
|
|
152
|
+
*/
|
|
153
|
+
completeStepUp(request: CompleteStepUpRequest): Promise<ElevatedProfileToken>;
|
|
154
|
+
/**
|
|
155
|
+
* Returns the active elevated token when it meets the requested freshness.
|
|
156
|
+
*
|
|
157
|
+
* @param request - Optional maximum session age in milliseconds, measured
|
|
158
|
+
* from when the token was obtained. Zero always requires a new ceremony.
|
|
159
|
+
* @returns A live elevated token, or null when no reusable session exists.
|
|
160
|
+
*/
|
|
161
|
+
getElevatedProfileToken(request?: GetElevatedTokenRequest): ElevatedProfileToken | null;
|
|
162
|
+
/**
|
|
163
|
+
* Clears the in-memory elevated session and its expiration timer.
|
|
164
|
+
*/
|
|
165
|
+
clearStepUpSession(): void;
|
|
125
166
|
performSignOut(): void;
|
|
126
167
|
/**
|
|
127
168
|
* Resets the controller to `defaultState`. Clients call this on wallet reset
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticationController.d.ts","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"AuthenticationController.d.ts","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,4BAA4B,CAAC;AAE9E,OAAO,KAAK,EACV,+BAA+B,EAC/B,0BAA0B,EAC1B,4BAA4B,EAC5B,0CAA0C,EAC3C,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EACV,gDAAgD,EAChD,0CAA0C,EAC3C,MAAM,0CAA0C,CAAC;AAYlD,OAAO,KAAK,EAEV,aAAa,EACb,YAAY,EAGZ,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGL,GAAG,EAKJ,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAOtE,OAAO,EAAE,qCAAqC,EAAE,MAAM,mDAAmD,CAAC;AAE1G,QAAA,MAAM,cAAc,6BAA6B,CAAC;AAGlD,MAAM,MAAM,6BAA6B,GAAG;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC/C;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC3C;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AACF,eAAO,MAAM,YAAY,EAAE,6BAK1B,CAAC;AAoEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C,KAAK,gBAAgB,GAAG;IACtB,GAAG,EAAE,GAAG,CAAC;IACT;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,OAAO,CAAC;CACvC,CAAC;AAuBF,MAAM,MAAM,OAAO,GACf,sCAAsC,GACtC,qCAAqC,CAAC;AAE1C,MAAM,MAAM,sCAAsC,GAAG,wBAAwB,CAC3E,OAAO,cAAc,EACrB,6BAA6B,CAC9B,CAAC;AAEF,MAAM,MAAM,wCAAwC,GAClD,0BAA0B,CACxB,OAAO,cAAc,EACrB,6BAA6B,CAC9B,CAAC;AAEJ,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,0CAA0C,GAAG;IACvD,IAAI,EAAE,GAAG,OAAO,cAAc,gBAAgB,CAAC;IAC/C,OAAO,EAAE,CAAC,iBAAiB,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,MAAM,GACd,wCAAwC,GACxC,0CAA0C,CAAC;AAG/C,KAAK,cAAc,GACf,+BAA+B,GAC/B,0CAA0C,GAC1C,0CAA0C,GAC1C,gDAAgD,CAAC;AAErD,KAAK,aAAa,GAAG,0BAA0B,GAAG,4BAA4B,CAAC;AAG/E,MAAM,MAAM,iCAAiC,GAAG,SAAS,CACvD,OAAO,cAAc,EACrB,OAAO,GAAG,cAAc,EACxB,MAAM,GAAG,aAAa,CACvB,CAAC;AAEF;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,cAAc,CAC1D,OAAO,cAAc,EACrB,6BAA6B,EAC7B,iCAAiC,CAClC;;IA0DC,YAAY,EACV,SAAS,EACT,KAAK,EACL,MAAM,EACN,WAAW,EACX,KAAK,GACN,EAAE;QACD,SAAS,EAAE,iCAAiC,CAAC;QAC7C,KAAK,CAAC,EAAE,6BAA6B,CAAC;QACtC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACnC;;;WAGG;QACH,WAAW,EAAE,eAAe,CAAC;QAC7B,KAAK,CAAC,EAAE,aAAa,CAAC;KACvB,EAkDA;IA4KY,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAiC9C;IA+GD;;;;OAIG;IACI,qBAAqB,IAAI,IAAI,CAOnC;IAuKD;;;;OAIG;IACU,0BAA0B,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA+BvE;IAED;;;;;OAKG;IACU,yBAAyB,CACpC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CAqB9B;IAED;;;;;;;;;;;;;OAaG;IACU,4BAA4B,CACvC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAyC/B;IAED;;;;;OAKG;IACU,WAAW,CACtB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,eAAe,CAAC,CAiB1B;IAED;;;;;;;;;OASG;IACU,cAAc,CACzB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAyC/B;IAED;;;;;;OAMG;IACI,uBAAuB,CAC5B,OAAO,GAAE,uBAA4B,GACpC,oBAAoB,GAAG,IAAI,CAoB7B;IA0BD;;OAEG;IACI,kBAAkB,IAAI,IAAI,CAWhC;IAoBM,cAAc,IAAI,IAAI,CAQ5B;IAED;;;OAGG;IACI,UAAU,IAAI,IAAI,CAMxB;IAED;;;;;;;;;;OAUG;IACU,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIrE;IAED;;;;;;;;;;;;OAYG;IACU,iBAAiB,CAC5B,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,WAAW,CAAC,CAItB;IAED;;;;;;;;;;;;;;;OAeG;IACU,yBAAyB,IAAI,OAAO,CAAC,MAAM,CAAC,CAgBxD;IAcY,qBAAqB,CAChC,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,kBAAkB,CAAC,CAI7B;IAED;;;;;;;;;;OAUG;IACU,uBAAuB,CAClC,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,CAIjB;IAED;;;;;;;;;;;;OAYG;IACU,uBAAuB,CAClC,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,iBAAiB,EAC3B,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,CAQjB;IAEM,UAAU,IAAI,OAAO,CAE3B;CA8EF"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { BaseController } from '@metamask/base-controller';
|
|
2
2
|
import { selectHdKeyringEntropySourceIds } from '@metamask/keyring-controller';
|
|
3
|
-
import { BeginEnrollmentRequestStruct, CompleteEnrollmentRequestStruct, assertValidMfaRequest, } from '../../sdk/authentication-jwt-bearer/mfa/schemas.js';
|
|
4
|
-
import { assertMessageStartsWithMetamask, AuthType, Env, JwtBearerAuth, PairConflictError, getMfaErrorCode, } from '../../sdk/index.js';
|
|
3
|
+
import { BeginEnrollmentRequestStruct, CompleteEnrollmentRequestStruct, assertValidMfaRequest, BeginStepUpRequestStruct, CompleteStepUpRequestStruct, GetElevatedTokenRequestStruct, parseElevatedTokenClaims, } from '../../sdk/authentication-jwt-bearer/mfa/schemas.js';
|
|
4
|
+
import { assertMessageStartsWithMetamask, AuthType, Env, JwtBearerAuth, PairConflictError, getMfaErrorCode, ElevatedTokenInvalidError, } from '../../sdk/index.js';
|
|
5
|
+
import { decodeJwtPayload } from '../../sdk/utils/jwt.js';
|
|
6
|
+
import { toErrorMessage } from '../../sdk/utils/to-error-message.js';
|
|
5
7
|
import { getPrimaryHdKeyringEntropySourceId } from '../../shared/utils/entropy-source.js';
|
|
6
8
|
import { getHdKeyringSeed } from '../../shared/utils/hd-keyring-seed.js';
|
|
7
9
|
import { getMessageSigningPublicKey, signMessageWithMessageSigningKey, } from '../../shared/utils/message-signing.js';
|
|
@@ -66,7 +68,19 @@ const metadata = {
|
|
|
66
68
|
includeInDebugSnapshot: false,
|
|
67
69
|
usedInUi: true,
|
|
68
70
|
},
|
|
71
|
+
stepUpSessionExpiresAt: {
|
|
72
|
+
includeInStateLogs: false,
|
|
73
|
+
persist: false,
|
|
74
|
+
includeInDebugSnapshot: false,
|
|
75
|
+
usedInUi: true,
|
|
76
|
+
},
|
|
69
77
|
};
|
|
78
|
+
/**
|
|
79
|
+
* Lifetime of an elevated session. Deliberately shorter than the
|
|
80
|
+
* elevated token's own `exp` so a fresh ceremony is required per sensitive
|
|
81
|
+
* action window, per the MFA phase-1 specification.
|
|
82
|
+
*/
|
|
83
|
+
export const STEP_UP_SESSION_TTL_MS = 60_000;
|
|
70
84
|
const MESSENGER_EXPOSED_METHODS = [
|
|
71
85
|
'performSignIn',
|
|
72
86
|
'performSignOut',
|
|
@@ -82,6 +96,10 @@ const MESSENGER_EXPOSED_METHODS = [
|
|
|
82
96
|
'refreshEnrolledCredentials',
|
|
83
97
|
'beginCredentialEnrollment',
|
|
84
98
|
'completeCredentialEnrollment',
|
|
99
|
+
'beginStepUp',
|
|
100
|
+
'completeStepUp',
|
|
101
|
+
'getElevatedProfileToken',
|
|
102
|
+
'clearStepUpSession',
|
|
85
103
|
];
|
|
86
104
|
/**
|
|
87
105
|
* Controller that enables authentication for restricted endpoints.
|
|
@@ -101,6 +119,8 @@ export class AuthenticationController extends BaseController {
|
|
|
101
119
|
* ceremony started under the previous session cannot apply its result.
|
|
102
120
|
*/
|
|
103
121
|
#authSessionEpoch = 0;
|
|
122
|
+
#stepUpSession = null;
|
|
123
|
+
#stepUpTimer;
|
|
104
124
|
/**
|
|
105
125
|
* Sequence number of the most recently started credentials refresh. Only
|
|
106
126
|
* that refresh may write the cache, so a slower, earlier request cannot
|
|
@@ -123,6 +143,7 @@ export class AuthenticationController extends BaseController {
|
|
|
123
143
|
this.messenger.subscribe('KeyringController:lock', () => {
|
|
124
144
|
this.#authSessionEpoch += 1;
|
|
125
145
|
this.#isUnlocked = false;
|
|
146
|
+
this.clearStepUpSession();
|
|
126
147
|
});
|
|
127
148
|
},
|
|
128
149
|
};
|
|
@@ -136,9 +157,10 @@ export class AuthenticationController extends BaseController {
|
|
|
136
157
|
if (!metametrics) {
|
|
137
158
|
throw new Error('`metametrics` field is required');
|
|
138
159
|
}
|
|
160
|
+
// `??` per key so an explicit `undefined` keeps the default rather than
|
|
161
|
+
// clobbering it.
|
|
139
162
|
this.#config = {
|
|
140
|
-
|
|
141
|
-
...config,
|
|
163
|
+
env: config?.env ?? this.#config.env,
|
|
142
164
|
isSocialPairingEnabled: config?.isSocialPairingEnabled ?? this.#config.isSocialPairingEnabled,
|
|
143
165
|
};
|
|
144
166
|
this.#metametrics = metametrics;
|
|
@@ -539,27 +561,43 @@ export class AuthenticationController extends BaseController {
|
|
|
539
561
|
* @returns The step's result.
|
|
540
562
|
*/
|
|
541
563
|
async #runMfaRequest(name, operation, credentialType, fn) {
|
|
542
|
-
const data = { outcome: 'pending' };
|
|
543
564
|
return await this.#trace({
|
|
544
565
|
name,
|
|
545
566
|
tags: { operation, credentialType },
|
|
546
|
-
|
|
547
|
-
}, async () => {
|
|
567
|
+
}, async (context) => {
|
|
548
568
|
try {
|
|
549
569
|
const result = await fn();
|
|
550
|
-
|
|
570
|
+
this.#setTraceAttribute(context, 'outcome', 'success');
|
|
551
571
|
return result;
|
|
552
572
|
}
|
|
553
573
|
catch (error) {
|
|
554
|
-
|
|
574
|
+
this.#setTraceAttribute(context, 'outcome', 'error');
|
|
555
575
|
const mfaCode = getMfaErrorCode(error);
|
|
556
576
|
if (mfaCode) {
|
|
557
|
-
|
|
577
|
+
this.#setTraceAttribute(context, 'mfaErrorCode', mfaCode);
|
|
578
|
+
if (mfaCode === 'authentication_required' && this.#isUnlocked) {
|
|
579
|
+
this.#invalidateSrpSession(this.#getPrimaryEntropySourceId());
|
|
580
|
+
// An elevated session must not outlive a rejected base session.
|
|
581
|
+
this.clearStepUpSession();
|
|
582
|
+
}
|
|
558
583
|
}
|
|
559
584
|
throw error;
|
|
560
585
|
}
|
|
561
586
|
});
|
|
562
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* `TraceContext` is opaque in `@metamask/controller-utils`; both clients
|
|
590
|
+
* hand back a Sentry span, so attributes are set via duck typing and a
|
|
591
|
+
* non-Sentry context is a silent no-op.
|
|
592
|
+
*
|
|
593
|
+
* @param context - Span handed to the trace callback, if any.
|
|
594
|
+
* @param key - Attribute name.
|
|
595
|
+
* @param value - Attribute value.
|
|
596
|
+
*/
|
|
597
|
+
#setTraceAttribute(context, key, value) {
|
|
598
|
+
const traceSpan = context;
|
|
599
|
+
traceSpan?.setAttribute?.(key, value);
|
|
600
|
+
}
|
|
563
601
|
/**
|
|
564
602
|
* Refreshes credentials enrolled on the canonical profile.
|
|
565
603
|
*
|
|
@@ -599,9 +637,13 @@ export class AuthenticationController extends BaseController {
|
|
|
599
637
|
const sessionEpoch = this.#authSessionEpoch;
|
|
600
638
|
assertValidMfaRequest(request, BeginEnrollmentRequestStruct);
|
|
601
639
|
const primaryEntropySourceId = this.#getPrimaryEntropySourceId();
|
|
640
|
+
// Enrolling beyond the first credential requires AAL2: send the elevated
|
|
641
|
+
// token while a session is live and let the server decide.
|
|
642
|
+
const accessToken = this.getElevatedProfileToken()?.accessToken;
|
|
602
643
|
const challenge = await this.#runMfaRequest('MFA Enroll Begin', request.reason.operation, request.type, async () => await this.#auth.beginMfaEnrollment(request.type, {
|
|
603
644
|
email: request.email,
|
|
604
645
|
entropySourceId: primaryEntropySourceId,
|
|
646
|
+
accessToken,
|
|
605
647
|
}));
|
|
606
648
|
this.#assertAuthSessionEpoch(sessionEpoch, 'beginCredentialEnrollment');
|
|
607
649
|
return challenge;
|
|
@@ -636,6 +678,8 @@ export class AuthenticationController extends BaseController {
|
|
|
636
678
|
}
|
|
637
679
|
throw error;
|
|
638
680
|
}
|
|
681
|
+
// The factor set changed: require a fresh ceremony against the new set.
|
|
682
|
+
this.clearStepUpSession();
|
|
639
683
|
try {
|
|
640
684
|
return await this.refreshEnrolledCredentials();
|
|
641
685
|
}
|
|
@@ -648,6 +692,117 @@ export class AuthenticationController extends BaseController {
|
|
|
648
692
|
}
|
|
649
693
|
}
|
|
650
694
|
}
|
|
695
|
+
/**
|
|
696
|
+
* Begins step-up verification with an enrolled credential.
|
|
697
|
+
*
|
|
698
|
+
* @param request - Credential type and trace reason.
|
|
699
|
+
* @returns A challenge for the client-owned ceremony.
|
|
700
|
+
*/
|
|
701
|
+
async beginStepUp(request) {
|
|
702
|
+
this.#assertIsUnlocked('beginStepUp');
|
|
703
|
+
const sessionEpoch = this.#authSessionEpoch;
|
|
704
|
+
assertValidMfaRequest(request, BeginStepUpRequestStruct);
|
|
705
|
+
const primaryEntropySourceId = this.#getPrimaryEntropySourceId();
|
|
706
|
+
const challenge = await this.#runMfaRequest('MFA Step-Up Begin', request.reason.operation, request.type, async () => await this.#auth.beginMfaVerification(request.type, primaryEntropySourceId));
|
|
707
|
+
this.#assertAuthSessionEpoch(sessionEpoch, 'beginStepUp');
|
|
708
|
+
return challenge;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Completes step-up verification and opens a short-lived elevated session.
|
|
712
|
+
*
|
|
713
|
+
* The AAL2 assertion returned by the MFA service is exchanged at Hydra for
|
|
714
|
+
* an elevated access token, whose claims are checked before the session
|
|
715
|
+
* opens. The token itself never enters controller state.
|
|
716
|
+
*
|
|
717
|
+
* @param request - Flow identifier, platform or email proof, and trace reason.
|
|
718
|
+
* @returns The elevated profile access token.
|
|
719
|
+
*/
|
|
720
|
+
async completeStepUp(request) {
|
|
721
|
+
this.#assertIsUnlocked('completeStepUp');
|
|
722
|
+
const sessionEpoch = this.#authSessionEpoch;
|
|
723
|
+
assertValidMfaRequest(request, CompleteStepUpRequestStruct);
|
|
724
|
+
const { type } = request.proof;
|
|
725
|
+
const { operation } = request.reason;
|
|
726
|
+
const primaryEntropySourceId = this.#getPrimaryEntropySourceId();
|
|
727
|
+
const assertion = await this.#runMfaRequest('MFA Step-Up Complete', operation, type, async () => await this.#auth.completeMfaVerification(request.flowId, request.proof, primaryEntropySourceId));
|
|
728
|
+
this.#assertAuthSessionEpoch(sessionEpoch, 'completeStepUp');
|
|
729
|
+
const accessToken = await this.#runMfaRequest('MFA Token Exchange', operation, type, async () => await this.#auth.exchangeMfaAssertion(assertion.token));
|
|
730
|
+
this.#assertAuthSessionEpoch(sessionEpoch, 'completeStepUp');
|
|
731
|
+
let decodedClaims;
|
|
732
|
+
try {
|
|
733
|
+
decodedClaims = decodeJwtPayload(accessToken.accessToken);
|
|
734
|
+
}
|
|
735
|
+
catch (error) {
|
|
736
|
+
throw new ElevatedTokenInvalidError(toErrorMessage(error));
|
|
737
|
+
}
|
|
738
|
+
const claims = parseElevatedTokenClaims(decodedClaims);
|
|
739
|
+
if (claims.exp * 1000 <= Date.now()) {
|
|
740
|
+
throw new ElevatedTokenInvalidError('Elevated token is expired');
|
|
741
|
+
}
|
|
742
|
+
const token = { ...accessToken, claims };
|
|
743
|
+
this.#openStepUpSession(token);
|
|
744
|
+
return token;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Returns the active elevated token when it meets the requested freshness.
|
|
748
|
+
*
|
|
749
|
+
* @param request - Optional maximum session age in milliseconds, measured
|
|
750
|
+
* from when the token was obtained. Zero always requires a new ceremony.
|
|
751
|
+
* @returns A live elevated token, or null when no reusable session exists.
|
|
752
|
+
*/
|
|
753
|
+
getElevatedProfileToken(request = {}) {
|
|
754
|
+
this.#assertIsUnlocked('getElevatedProfileToken');
|
|
755
|
+
assertValidMfaRequest(request, GetElevatedTokenRequestStruct);
|
|
756
|
+
const session = this.#stepUpSession;
|
|
757
|
+
if (!session) {
|
|
758
|
+
return null;
|
|
759
|
+
}
|
|
760
|
+
const now = Date.now();
|
|
761
|
+
if (now >= session.expiresAt) {
|
|
762
|
+
// The hard-expiry timer has not fired yet (e.g. a suspended tab).
|
|
763
|
+
this.clearStepUpSession();
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
// `>=` so a zero max age always forces a fresh ceremony. Not cleared: the
|
|
767
|
+
// max age is this caller's requirement; others may still use the session.
|
|
768
|
+
const maxAge = request.maxSessionAgeMs;
|
|
769
|
+
if (maxAge !== undefined && now - session.token.obtainedAt >= maxAge) {
|
|
770
|
+
return null;
|
|
771
|
+
}
|
|
772
|
+
return session.token;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Opens the elevated session. Its lifetime is the session TTL clamped to
|
|
776
|
+
* the token's own `exp`, so the session never outlives the token.
|
|
777
|
+
*
|
|
778
|
+
* @param token - The freshly exchanged elevated token.
|
|
779
|
+
*/
|
|
780
|
+
#openStepUpSession(token) {
|
|
781
|
+
this.clearStepUpSession();
|
|
782
|
+
const expiresAt = Math.min(token.obtainedAt + STEP_UP_SESSION_TTL_MS, token.claims.exp * 1000);
|
|
783
|
+
this.#stepUpSession = { token, expiresAt };
|
|
784
|
+
this.update((state) => {
|
|
785
|
+
state.stepUpSessionExpiresAt = expiresAt;
|
|
786
|
+
});
|
|
787
|
+
this.#stepUpTimer = setTimeout(() => this.clearStepUpSession(), Math.max(0, expiresAt - Date.now()));
|
|
788
|
+
// Never keep a Node process alive for the expiry timer (tests, tooling).
|
|
789
|
+
this.#stepUpTimer.unref?.();
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Clears the in-memory elevated session and its expiration timer.
|
|
793
|
+
*/
|
|
794
|
+
clearStepUpSession() {
|
|
795
|
+
if (this.#stepUpTimer !== undefined) {
|
|
796
|
+
clearTimeout(this.#stepUpTimer);
|
|
797
|
+
this.#stepUpTimer = undefined;
|
|
798
|
+
}
|
|
799
|
+
this.#stepUpSession = null;
|
|
800
|
+
if (this.state.stepUpSessionExpiresAt !== undefined) {
|
|
801
|
+
this.update((state) => {
|
|
802
|
+
state.stepUpSessionExpiresAt = undefined;
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
}
|
|
651
806
|
/**
|
|
652
807
|
* Drops the cached credential list. Callers that wipe profile state must go
|
|
653
808
|
* through this so subscribers never keep credentials belonging to a profile
|
|
@@ -666,6 +821,7 @@ export class AuthenticationController extends BaseController {
|
|
|
666
821
|
}
|
|
667
822
|
performSignOut() {
|
|
668
823
|
this.#authSessionEpoch += 1;
|
|
824
|
+
this.clearStepUpSession();
|
|
669
825
|
this.#clearEnrolledCredentials();
|
|
670
826
|
this.update((state) => {
|
|
671
827
|
state.isSignedIn = false;
|
|
@@ -679,6 +835,7 @@ export class AuthenticationController extends BaseController {
|
|
|
679
835
|
clearState() {
|
|
680
836
|
this.#profilePairingRequestEpoch += 1;
|
|
681
837
|
this.#authSessionEpoch += 1;
|
|
838
|
+
this.clearStepUpSession();
|
|
682
839
|
this.#clearEnrolledCredentials();
|
|
683
840
|
this.update(() => ({ ...defaultState }));
|
|
684
841
|
}
|