From 1f0e0ca0980858f04eeb64aae04c2ffdd43517ad Mon Sep 17 00:00:00 2001
From: rr-bw <102181210+rr-bw@users.noreply.github.com>
Date: Fri, 30 Jan 2026 15:11:59 -0800
Subject: [PATCH] refactor(input-password-flows): [Auth/PM-27086] JIT MP org
user flow - remove masterKey generation from InputPasswordComponent (#18006)
- Updates `InputPasswordComponent` to emit raw data instead of generating cryptographic properties (`newMasterKey`, `newServerMasterKeyHash`, `newLocalMasterKeyHash`).
- This helps us in moving away from using the deprecated `makeMasterKey()` method in the component (which takes email as salt) as we seek to eventually separate the email from the salt.
- Updates the `JIT_PROVISIONED_MP_ORG_USER` case of the switch to handle the flow when the `PM27086_UpdateAuthenticationApisForInputPassword` flag is on.
Feature Flag: `PM27086_UpdateAuthenticationApisForInputPassword`
---
...sktop-set-initial-password.service.spec.ts | 6 ++
.../desktop-set-initial-password.service.ts | 3 +
.../web-set-initial-password.service.spec.ts | 6 ++
.../web-set-initial-password.service.ts | 3 +
...initial-password.service.implementation.ts | 9 +++
...fault-set-initial-password.service.spec.ts | 4 +
.../set-initial-password.component.ts | 64 ++++++++++++++-
...et-initial-password.service.abstraction.ts | 2 +
.../input-password.component.ts | 46 ++++++++++-
.../angular/input-password/input-password.mdx | 81 +++++++------------
.../input-password/input-password.stories.ts | 8 ++
.../input-password/password-input-result.ts | 14 ++++
libs/common/src/enums/feature-flag.enum.ts | 2 +
13 files changed, 189 insertions(+), 59 deletions(-)
diff --git a/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts
index 9bb7d5077cf..430870a247b 100644
--- a/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts
+++ b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts
@@ -87,6 +87,10 @@ describe("DesktopSetInitialPasswordService", () => {
expect(sut).not.toBeFalsy();
});
+ /**
+ * @deprecated To be removed in PM-28143. When you remove this, check also if there are any imports/properties
+ * in the test setup above that are now un-used and can also be removed.
+ */
describe("setInitialPassword(...)", () => {
// Mock function parameters
let credentials: SetInitialPasswordCredentials;
@@ -116,6 +120,8 @@ describe("DesktopSetInitialPasswordService", () => {
orgSsoIdentifier: "orgSsoIdentifier",
orgId: "orgId",
resetPasswordAutoEnroll: false,
+ newPassword: "Test@Password123!",
+ salt: "user@example.com" as MasterPasswordSalt,
};
userId = "userId" as UserId;
userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER;
diff --git a/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts
index f9fb8361056..3b1562075f9 100644
--- a/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts
+++ b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts
@@ -54,6 +54,9 @@ export class DesktopSetInitialPasswordService
);
}
+ /**
+ * @deprecated To be removed in PM-28143
+ */
override async setInitialPassword(
credentials: SetInitialPasswordCredentials,
userType: SetInitialPasswordUserType,
diff --git a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts
index b09b5f0bc9a..ead40739a50 100644
--- a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts
+++ b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts
@@ -90,6 +90,10 @@ describe("WebSetInitialPasswordService", () => {
expect(sut).not.toBeFalsy();
});
+ /**
+ * @deprecated To be removed in PM-28143. When you remove this, check also if there are any imports/properties
+ * in the test setup above that are now un-used and can also be removed.
+ */
describe("setInitialPassword(...)", () => {
// Mock function parameters
let credentials: SetInitialPasswordCredentials;
@@ -119,6 +123,8 @@ describe("WebSetInitialPasswordService", () => {
orgSsoIdentifier: "orgSsoIdentifier",
orgId: "orgId",
resetPasswordAutoEnroll: false,
+ newPassword: "Test@Password123!",
+ salt: "user@example.com" as MasterPasswordSalt,
};
userId = "userId" as UserId;
userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER;
diff --git a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts
index 0b8dba6c40e..a6a902ab847 100644
--- a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts
+++ b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts
@@ -56,6 +56,9 @@ export class WebSetInitialPasswordService
);
}
+ /**
+ * @deprecated To be removed in PM-28143
+ */
override async setInitialPassword(
credentials: SetInitialPasswordCredentials,
userType: SetInitialPasswordUserType,
diff --git a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts
index 3f6023c1205..85177a920e3 100644
--- a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts
+++ b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts
@@ -63,6 +63,10 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
protected registerSdkService: RegisterSdkService,
) {}
+ /**
+ * @deprecated To be removed in PM-28143. When you remove this, also check for any objects/methods
+ * in this default service that are now un-used and can also be removed.
+ */
async setInitialPassword(
credentials: SetInitialPasswordCredentials,
userType: SetInitialPasswordUserType,
@@ -333,6 +337,9 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
);
}
+ /**
+ * @deprecated To be removed in PM-28143
+ */
private async makeMasterKeyEncryptedUserKey(
masterKey: MasterKey,
userId: UserId,
@@ -410,6 +417,8 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
}
/**
+ * @deprecated To be removed in PM-28143
+ *
* As part of [PM-28494], adding this setting path to accommodate the changes that are
* emerging with pm-23246-unlock-with-master-password-unlock-data.
* Without this, immediately locking/unlocking the vault with the new password _may_ still fail
diff --git a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts
index 6b3981a5231..91578fdd7b6 100644
--- a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts
+++ b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts
@@ -124,6 +124,10 @@ describe("DefaultSetInitialPasswordService", () => {
expect(sut).not.toBeFalsy();
});
+ /**
+ * @deprecated To be removed in PM-28143. When you remove this, check also if there are any imports/properties
+ * in the test setup above that are now un-used and can also be removed.
+ */
describe("setInitialPassword(...)", () => {
// Mock function parameters
let credentials: SetInitialPasswordCredentials;
diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts
index 4ab26ecd09e..7850a980eef 100644
--- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts
+++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts
@@ -29,6 +29,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
+import { HashPurpose } from "@bitwarden/common/platform/enums";
import { SyncService } from "@bitwarden/common/platform/sync";
import { OrganizationId, UserId } from "@bitwarden/common/types/guid";
import {
@@ -38,6 +39,7 @@ import {
DialogService,
ToastService,
} from "@bitwarden/components";
+import { KeyService } from "@bitwarden/key-management";
import { I18nPipe } from "@bitwarden/ui-common";
import {
@@ -76,6 +78,7 @@ export class SetInitialPasswordComponent implements OnInit {
private anonLayoutWrapperDataService: AnonLayoutWrapperDataService,
private dialogService: DialogService,
private i18nService: I18nService,
+ private keyService: KeyService,
private logoutService: LogoutService,
private logService: LogService,
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
@@ -110,16 +113,72 @@ export class SetInitialPasswordComponent implements OnInit {
switch (this.userType) {
case SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER: {
+ /**
+ * "KM flag" = EnableAccountEncryptionV2JitPasswordRegistration
+ * "Auth flag" = PM27086_UpdateAuthenticationApisForInputPassword (checked in InputPasswordComponent and
+ * passed through via PasswordInputResult)
+ *
+ * Flag unwinding for this specific `case` will depend on which flag gets unwound first:
+ * - If KM flag gets unwound first, remove all code (in this `case`) after the call
+ * to setInitialPasswordJitMPUserV2Encryption(), as the V2Encryption method is the
+ * end-goal for this `case`.
+ * - If Auth flag gets unwound first (in PM-28143), keep the KM code & early return,
+ * but unwind the auth flagging logic and then remove the method call marked with
+ * the "Default Scenario" comment.
+ */
+
const accountEncryptionV2 = await this.configService.getFeatureFlag(
FeatureFlag.EnableAccountEncryptionV2JitPasswordRegistration,
);
+ // Scenario 1: KM flag ON
if (accountEncryptionV2) {
await this.setInitialPasswordJitMPUserV2Encryption(passwordInputResult);
return;
}
- await this.setInitialPassword(passwordInputResult);
+ // Scenario 2: KM flag OFF, Auth flag ON
+ if (passwordInputResult.newApisWithInputPasswordFlagEnabled) {
+ /**
+ * If the Auth flag is enabled, it means the InputPasswordComponent will not emit a newMasterKey,
+ * newServerMasterKeyHash, and newLocalMasterKeyHash. So we must create them here and add them late
+ * to the PasswordInputResult before calling setInitialPassword().
+ *
+ * This is a temporary state. The end-goal will be to use KM's V2Encryption method above.
+ */
+ const ctx = "Could not set initial password.";
+ assertTruthy(passwordInputResult.newPassword, "newPassword", ctx);
+ assertNonNullish(passwordInputResult.kdfConfig, "kdfConfig", ctx);
+ assertTruthy(this.email, "email", ctx);
+
+ const newMasterKey = await this.keyService.makeMasterKey(
+ passwordInputResult.newPassword,
+ this.email.trim().toLowerCase(),
+ passwordInputResult.kdfConfig,
+ );
+
+ const newServerMasterKeyHash = await this.keyService.hashMasterKey(
+ passwordInputResult.newPassword,
+ newMasterKey,
+ HashPurpose.ServerAuthorization,
+ );
+
+ const newLocalMasterKeyHash = await this.keyService.hashMasterKey(
+ passwordInputResult.newPassword,
+ newMasterKey,
+ HashPurpose.LocalAuthorization,
+ );
+
+ passwordInputResult.newMasterKey = newMasterKey;
+ passwordInputResult.newServerMasterKeyHash = newServerMasterKeyHash;
+ passwordInputResult.newLocalMasterKeyHash = newLocalMasterKeyHash;
+
+ await this.setInitialPassword(passwordInputResult); // passwordInputResult masterKey properties generated on the SetInitialPasswordComponent (just above)
+ return;
+ }
+
+ // Default Scenario: both flags OFF
+ await this.setInitialPassword(passwordInputResult); // passwordInputResult masterKey properties generated on the InputPasswordComponent (default)
break;
}
@@ -274,6 +333,9 @@ export class SetInitialPasswordComponent implements OnInit {
}
}
+ /**
+ * @deprecated To be removed in PM-28143
+ */
private async setInitialPassword(passwordInputResult: PasswordInputResult) {
const ctx = "Could not set initial password.";
assertTruthy(passwordInputResult.newMasterKey, "newMasterKey", ctx);
diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts
index 2667040c707..70318be3393 100644
--- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts
+++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts
@@ -87,6 +87,8 @@ export interface InitializeJitPasswordCredentials {
*/
export abstract class SetInitialPasswordService {
/**
+ * @deprecated To be removed in PM-28143
+ *
* Sets an initial password for an existing authed user who is either:
* - {@link SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER}
* - {@link SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP}
diff --git a/libs/auth/src/angular/input-password/input-password.component.ts b/libs/auth/src/angular/input-password/input-password.component.ts
index 62294f037a0..b81e01156f1 100644
--- a/libs/auth/src/angular/input-password/input-password.component.ts
+++ b/libs/auth/src/angular/input-password/input-password.component.ts
@@ -10,7 +10,9 @@ import {
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
+import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
+import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
@@ -209,6 +211,7 @@ export class InputPasswordComponent implements OnInit {
constructor(
private auditService: AuditService,
private cipherService: CipherService,
+ private configService: ConfigService,
private dialogService: DialogService,
private formBuilder: FormBuilder,
private i18nService: I18nService,
@@ -312,7 +315,7 @@ export class InputPasswordComponent implements OnInit {
}
if (!this.email) {
- throw new Error("Email is required to create master key.");
+ throw new Error("Email not found.");
}
// 1. Determine kdfConfig
@@ -320,13 +323,13 @@ export class InputPasswordComponent implements OnInit {
this.kdfConfig = DEFAULT_KDF_CONFIG;
} else {
if (!this.userId) {
- throw new Error("userId not passed down");
+ throw new Error("userId not found.");
}
this.kdfConfig = await firstValueFrom(this.kdfConfigService.getKdfConfig$(this.userId));
}
if (this.kdfConfig == null) {
- throw new Error("KdfConfig is required to create master key.");
+ throw new Error("KdfConfig not found.");
}
const salt =
@@ -334,7 +337,7 @@ export class InputPasswordComponent implements OnInit {
? await firstValueFrom(this.masterPasswordService.saltForUser$(this.userId))
: this.masterPasswordService.emailToSalt(this.email);
if (salt == null) {
- throw new Error("Salt is required to create master key.");
+ throw new Error("Salt not found.");
}
// 2. Verify current password is correct (if necessary)
@@ -361,6 +364,41 @@ export class InputPasswordComponent implements OnInit {
return;
}
+ // When you unwind the flag in PM-28143, also remove the ConfigService if it is un-used.
+ const newApisWithInputPasswordFlagEnabled = await this.configService.getFeatureFlag(
+ FeatureFlag.PM27086_UpdateAuthenticationApisForInputPassword,
+ );
+
+ if (newApisWithInputPasswordFlagEnabled) {
+ // 4. Build a PasswordInputResult object
+ const passwordInputResult: PasswordInputResult = {
+ newPassword,
+ kdfConfig: this.kdfConfig,
+ salt,
+ newPasswordHint,
+ newApisWithInputPasswordFlagEnabled, // To be removed in PM-28143
+ };
+
+ if (
+ this.flow === InputPasswordFlow.ChangePassword ||
+ this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation
+ ) {
+ passwordInputResult.currentPassword = currentPassword;
+ }
+
+ if (this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation) {
+ passwordInputResult.rotateUserKey = this.formGroup.controls.rotateUserKey?.value;
+ }
+
+ // 5. Emit and return PasswordInputResult object
+ this.onPasswordFormSubmit.emit(passwordInputResult);
+ return passwordInputResult;
+ }
+
+ /*******************************************************************
+ * The following code (within this `try`) to be removed in PM-28143
+ *******************************************************************/
+
// 4. Create cryptographic keys and build a PasswordInputResult object
const newMasterKey = await this.keyService.makeMasterKey(
newPassword,
diff --git a/libs/auth/src/angular/input-password/input-password.mdx b/libs/auth/src/angular/input-password/input-password.mdx
index e3cdcbf08b9..4b174658d16 100644
--- a/libs/auth/src/angular/input-password/input-password.mdx
+++ b/libs/auth/src/angular/input-password/input-password.mdx
@@ -6,14 +6,12 @@ import * as stories from "./input-password.stories.ts";
# InputPassword Component
-The `InputPasswordComponent` allows a user to enter master password related credentials.
-Specifically, it does the following:
+The `InputPasswordComponent` allows a user to enter a new master password for the purpose of setting
+an initial password or changing an existing password. Specifically, it does the following:
1. Displays form fields in the UI
2. Validates form fields
-3. Generates cryptographic properties based on the form inputs (e.g. `newMasterKey`,
- `newServerMasterKeyHash`, etc.)
-4. Emits the generated properties to the parent component
+3. Emits values to the parent component
The `InputPasswordComponent` is central to our set/change password flows, allowing us to keep our
form UI and validation logic consistent. As such, it is intended for re-use in different set/change
@@ -30,7 +28,6 @@ those values as needed.
- [The InputPasswordFlow](#the-inputpasswordflow)
- [Use Cases](#use-cases)
- [HTML - Form Fields](#html---form-fields)
- - [TypeScript - Credential Generation](#typescript---credential-generation)
- [Difference between SetInitialPasswordAccountRegistration and SetInitialPasswordAuthedUser](#difference-between-setinitialpasswordaccountregistration-and-setinitialpasswordautheduser)
- [Validation](#validation)
- [Submit Logic](#submit-logic)
@@ -44,20 +41,20 @@ those values as needed.
**Required**
- `flow` - the parent component must provide an `InputPasswordFlow`, which is used to determine
- which form input elements will be displayed in the UI and which cryptographic keys will be created
- and emitted. [Click here](#the-inputpasswordflow) to learn more about the different
- `InputPasswordFlow` options.
+ which form input elements will be displayed in the UI and which values will be emitted.
+ [Click here](#the-inputpasswordflow) to learn more about the different `InputPasswordFlow`
+ options.
**Optional (sometimes)**
-These two `@Inputs` are optional on some flows, but required on others. Therefore these `@Inputs`
-are not marked as `{ required: true }`, but there _is_ component logic that ensures (requires) that
-the `email` and/or `userId` is present in certain flows, while not present in other flows.
+These `@Inputs` are optional on some flows, but required on others. Therefore these `@Inputs` are
+not marked as `{ required: true }`, but there _is_ component logic that ensures (requires) that the
+`email` and/or `userId` is present in certain flows, while not present in other flows.
-- `email` - allows the `InputPasswordComponent` to generate a master key
+- `email` - allows the `InputPasswordComponent` to use the email as a salt (if needed)
- `userId` - allows the `InputPasswordComponent` to do things like get the user's `kdfConfig`,
- verify that a current password is correct, and perform validation prior to user key rotation on
- the parent
+ verify that a current password is correct, and perform validation prior to user key rotation (if
+ selected) on the parent
**Optional**
@@ -87,8 +84,7 @@ These `@Inputs` are truly optional.
## The `InputPasswordFlow`
The `InputPasswordFlow` is a crucial and required `@Input` that influences both the HTML and the
-credential generation logic of the component. It is important for the dev to understand when to use
-each flow.
+logic of the component. It is important for the dev to understand when to use each flow.
### Use Cases
@@ -106,8 +102,9 @@ Used in scenarios where we do have an existing and authed user, and thus an acti
- A "just-in-time" (JIT) provisioned user joins a master password (MP) encryption org and must set
their initial password
-- A "just-in-time" (JIT) provisioned user joins a trusted device encryption (TDE) org with a
- starting role that requires them to have/set their initial password
+- A "just-in-time" (JIT) provisioned user joins a trusted device encryption (TDE) org with the reset
+ password permission ("manage account recovery") from the start, which requires them to have/set
+ their initial password
- A note on JIT provisioned user flows:
- Even though a JIT provisioned user is a brand-new user who was “just” created, we consider
them to be an “existing authed user” _from the perspective of the set-password flow_. This is
@@ -117,8 +114,9 @@ Used in scenarios where we do have an existing and authed user, and thus an acti
registration when a user reaches the `/finish-signup` or `/trial-initiation` page to set their
initial password, their account does not yet exist in the database, and will only be created
once they set an initial password.
-- An existing user in a TDE org logs in after the org admin upgraded the user to a role that now
- requires them to have/set their initial password
+- An existing user in a TDE org logs in after an org admin upgraded the user to have the reset
+ password persmission ("manage account recovery"), which now requires the user to have/set their
+ initial password
- An existing user logs in after their org admin offboarded the org from TDE, and the user must now
have/set their initial password
@@ -126,7 +124,7 @@ Used in scenarios where we do have an existing and authed user, and thus an acti
Used in scenarios where we simply want to offer the user the ability to change their password:
-- User clicks an org email invite link an logs in with their password which does not meet the org's
+- User clicks an org email invite link and logs in with their password which does not meet the org's
policy requirements
- User logs in with password that does not meet the org's policy requirements
- User logs in after their password was reset via Account Recovery (and now they must change their
@@ -156,26 +154,10 @@ which form field UI elements get displayed.
-### TypeScript - Credential Generation
-
-- **`SetInitialPasswordAccountRegistration`** and **`SetInitialPasswordAuthedUser`**
- - These flows involve a user setting their password for the first time. Therefore on submit the
- component will only generate new credentials (`newMasterKey`) and not current credentials
- (`currentMasterKey`).
-- **`ChangePassword`** and **`ChangePasswordWithOptionalUserKeyRotation`**
- - These flows both require the user to enter a current password along with a new password.
- Therefore on submit the component will generate current credentials (`currentMasterKey`) along
- with new credentials (`newMasterKey`).
-- **`ChangePasswordDelegation`**
- - This flow does not generate any credentials, but simply validates the new password and emits it
- up to the parent.
-
-
-
### Difference between `SetInitialPasswordAccountRegistration` and `SetInitialPasswordAuthedUser`
-These two flows are similar in that they display the same form fields and only generate new
-credentials, but we need to keep them separate for the following reasons:
+These two flows are similar in that they display the same form fields, but we need to keep them
+separate for the following reasons:
- `SetInitialPasswordAccountRegistration` involves scenarios where we have no existing user, and
**thus NO active account `userId`**:
@@ -183,7 +165,7 @@ credentials, but we need to keep them separate for the following reasons:
and **thus an active account `userId`**:
The presence or absence of an active account `userId` is important because it determines how we get
-the correct `kdfConfig` prior to key generation:
+the correct `kdfConfig`:
- If there is no `userId` passed down from the parent, we default to `DEFAULT_KDF_CONFIG`
- If there is a `userId` passed down from the parent, we get the `kdfConfig` from state using the
@@ -223,25 +205,16 @@ When the form is submitted, the `InputPasswordComponent` does the following in o
checkbox)
- Checks that the new password adheres to any enforced master password policies that were
optionally passed down by the parent
-2. Uses the form inputs to create cryptographic properties (`newMasterKey`,
- `newServerMasterKeyHash`, etc.)
-3. Emits those cryptographic properties up to the parent (along with other values defined in
- `PasswordInputResult`) to be used by the parent as needed.
+2. Emits values up to the parent (along with other values defined in `PasswordInputResult`) to be
+ used by the parent as needed.
```typescript
export interface PasswordInputResult {
currentPassword?: string;
- currentMasterKey?: MasterKey;
- currentServerMasterKeyHash?: string;
- currentLocalMasterKeyHash?: string;
-
newPassword: string;
- newPasswordHint?: string;
- newMasterKey?: MasterKey;
- newServerMasterKeyHash?: string;
- newLocalMasterKeyHash?: string;
-
kdfConfig?: KdfConfig;
+ salt?: MasterPasswordSalt;
+ newPasswordHint?: string;
rotateUserKey?: boolean;
}
```
diff --git a/libs/auth/src/angular/input-password/input-password.stories.ts b/libs/auth/src/angular/input-password/input-password.stories.ts
index 285ce94b269..9e3a6419d2a 100644
--- a/libs/auth/src/angular/input-password/input-password.stories.ts
+++ b/libs/auth/src/angular/input-password/input-password.stories.ts
@@ -10,6 +10,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
+import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
@@ -59,6 +60,13 @@ export default {
getAllDecrypted: () => Promise.resolve([]),
},
},
+ // Can remove ConfigService from component and stories in PM-28143 (if it is no longer used)
+ {
+ provide: ConfigService,
+ useValue: {
+ getFeatureFlag: () => false, // default to false since flag does not effect UI
+ },
+ },
{
provide: KdfConfigService,
useValue: {
diff --git a/libs/auth/src/angular/input-password/password-input-result.ts b/libs/auth/src/angular/input-password/password-input-result.ts
index 11c8f0d274d..575302a9ee0 100644
--- a/libs/auth/src/angular/input-password/password-input-result.ts
+++ b/libs/auth/src/angular/input-password/password-input-result.ts
@@ -10,6 +10,20 @@ export interface PasswordInputResult {
newPasswordHint?: string;
rotateUserKey?: boolean;
+ /**
+ * Temporary property that persists the flag state through the entire set/change password process.
+ * This allows flows to consume this value instead of re-checking the flag state via ConfigService themselves.
+ *
+ * The ChangePasswordDelegation flows (Emergency Access Takeover and Account Recovery), however, only ever
+ * require a raw newPassword from the InputPasswordComponent regardless of whether the flag is on or off.
+ * Flagging for those 2 flows will be done via the ConfigService in their respective services.
+ *
+ * To be removed in PM-28143
+ */
+ newApisWithInputPasswordFlagEnabled?: boolean;
+
+ // The deprecated properties below will be removed in PM-28143: https://bitwarden.atlassian.net/browse/PM-28143
+
/** @deprecated This low-level cryptographic state will be removed. It will be replaced by high level calls to masterpassword service, in the consumers of this interface. */
currentMasterKey?: MasterKey;
/** @deprecated */
diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts
index 9d9de56c608..dc960baae1d 100644
--- a/libs/common/src/enums/feature-flag.enum.ts
+++ b/libs/common/src/enums/feature-flag.enum.ts
@@ -18,6 +18,7 @@ export enum FeatureFlag {
/* Auth */
PM23801_PrefetchPasswordPrelogin = "pm-23801-prefetch-password-prelogin",
+ PM27086_UpdateAuthenticationApisForInputPassword = "pm-27086-update-authentication-apis-for-input-password",
SafariAccountSwitching = "pm-5594-safari-account-switching",
/* Autofill */
@@ -137,6 +138,7 @@ export const DefaultFeatureFlagValue = {
/* Auth */
[FeatureFlag.PM23801_PrefetchPasswordPrelogin]: FALSE,
+ [FeatureFlag.PM27086_UpdateAuthenticationApisForInputPassword]: FALSE,
[FeatureFlag.SafariAccountSwitching]: FALSE,
/* Billing */