diff --git a/apps/web/src/app/auth/settings/account/account.component.html b/apps/web/src/app/auth/settings/account/account.component.html
index a5e5329fce..6d72ad1037 100644
--- a/apps/web/src/app/auth/settings/account/account.component.html
+++ b/apps/web/src/app/auth/settings/account/account.component.html
@@ -4,7 +4,7 @@
-
{{ "changeEmail" | i18n }}
+
{{ "areYouTryingtoLogin" | i18n }}
@@ -29,4 +29,11 @@
+
+
+
+
+
diff --git a/apps/web/src/app/auth/settings/account/account.component.ts b/apps/web/src/app/auth/settings/account/account.component.ts
index 51bf427696..3d2084237c 100644
--- a/apps/web/src/app/auth/settings/account/account.component.ts
+++ b/apps/web/src/app/auth/settings/account/account.component.ts
@@ -2,6 +2,7 @@ import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
import { combineLatest, from, lastValueFrom, map, Observable } from "rxjs";
import { ModalService } from "@bitwarden/angular/services/modal.service";
+import { LoginApprovalComponent } from "@bitwarden/auth/angular";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
@@ -78,4 +79,15 @@ export class AccountComponent implements OnInit {
const dialogRef = DeleteAccountDialogComponent.open(this.dialogService);
await lastValueFrom(dialogRef.closed);
};
+
+ // TODO: remove this - for testing only
+ openLoginApproval() {
+ LoginApprovalComponent.open(this.dialogService, {
+ data: {
+ name: "test name",
+ userId: "yourUserId",
+ fingerprint: "test fingerprint",
+ },
+ });
+ }
}
diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json
index 3189777aa7..41c857d2a4 100644
--- a/apps/web/src/locales/en/messages.json
+++ b/apps/web/src/locales/en/messages.json
@@ -86,6 +86,12 @@
"atRiskApplications": {
"message": "At-risk applications"
},
+ "deviceType": {
+ "message": "Device type"
+ },
+ "ipAddress": {
+ "message": "IP address"
+ },
"totalApplications": {
"message": "Total applications"
},
diff --git a/libs/auth/src/angular/index.ts b/libs/auth/src/angular/index.ts
index d3d9e60091..9e30fd89dd 100644
--- a/libs/auth/src/angular/index.ts
+++ b/libs/auth/src/angular/index.ts
@@ -58,3 +58,6 @@ export * from "./vault-timeout-input/vault-timeout-input.component";
// self hosted environment configuration dialog
export * from "./self-hosted-env-config-dialog/self-hosted-env-config-dialog.component";
+
+// login approval
+export * from "./login/login-approval.component";
diff --git a/libs/auth/src/angular/login/login-approval.component.html b/libs/auth/src/angular/login/login-approval.component.html
new file mode 100644
index 0000000000..c30e6a1038
--- /dev/null
+++ b/libs/auth/src/angular/login/login-approval.component.html
@@ -0,0 +1,28 @@
+
diff --git a/libs/auth/src/angular/login/login-approval.component.ts b/libs/auth/src/angular/login/login-approval.component.ts
new file mode 100644
index 0000000000..98037eb62f
--- /dev/null
+++ b/libs/auth/src/angular/login/login-approval.component.ts
@@ -0,0 +1,70 @@
+import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
+import { CommonModule } from "@angular/common";
+import { Component, Inject, OnInit } from "@angular/core";
+import { FormGroup, ReactiveFormsModule } from "@angular/forms";
+import { RouterLink } from "@angular/router";
+
+import { JslibModule } from "@bitwarden/angular/jslib.module";
+import {
+ AsyncActionsModule,
+ ButtonModule,
+ DialogModule,
+ DialogService,
+ FormFieldModule,
+} from "@bitwarden/components";
+
+export type LoginApprovalDialogData = {
+ name: string;
+ userId: string;
+ fingerprint: string;
+};
+
+@Component({
+ selector: "login-approval",
+ templateUrl: "login-approval.component.html",
+ standalone: true,
+ imports: [
+ CommonModule,
+ JslibModule,
+ ReactiveFormsModule,
+ FormFieldModule,
+ AsyncActionsModule,
+ RouterLink,
+ ButtonModule,
+ DialogModule,
+ ],
+})
+export class LoginApprovalComponent implements OnInit {
+ name: string;
+ userId: string;
+ fingerprint: string;
+
+ loading = true;
+ formPromise: Promise;
+
+ formGroup = new FormGroup({});
+
+ constructor(
+ @Inject(DIALOG_DATA) protected data: LoginApprovalDialogData,
+ private dialogRef: DialogRef,
+ ) {
+ this.name = data.name;
+ this.userId = data.userId;
+ }
+
+ async ngOnInit() {
+ this.loading = false;
+ }
+
+ submit = async () => {
+ if (this.loading) {
+ return;
+ }
+
+ this.dialogRef.close();
+ };
+
+ static open(dialogService: DialogService, config: DialogConfig) {
+ return dialogService.open(LoginApprovalComponent, config);
+ }
+}