diff --git a/libs/auth/src/angular/login/login.component.html b/libs/auth/src/angular/login/login.component.html
index 364e200e65..75e8f1de86 100644
--- a/libs/auth/src/angular/login/login.component.html
+++ b/libs/auth/src/angular/login/login.component.html
@@ -147,32 +147,13 @@
{{ "continue" | i18n }}
-
-
-
+
-
-
+
+
+
diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts
index eb0e559c00..01f9c23855 100644
--- a/libs/auth/src/angular/login/login.component.ts
+++ b/libs/auth/src/angular/login/login.component.ts
@@ -16,12 +16,14 @@ import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.d
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
+import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { CaptchaIFrame } from "@bitwarden/common/auth/captcha-iframe";
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
import { ClientType } from "@bitwarden/common/enums";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
+import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
@@ -38,6 +40,7 @@ import {
IconButtonModule,
ToastService,
} from "@bitwarden/components";
+import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper-data.service";
import { WaveIcon } from "../icons";
@@ -117,6 +120,7 @@ export class LoginComponent implements OnInit, OnDestroy {
private anonLayoutWrapperDataService: AnonLayoutWrapperDataService,
private appIdService: AppIdService,
private broadcasterService: BroadcasterService,
+ private cryptoFunctionService: CryptoFunctionService,
private devicesApiService: DevicesApiServiceAbstraction,
private environmentService: EnvironmentService,
private formBuilder: FormBuilder,
@@ -126,11 +130,13 @@ export class LoginComponent implements OnInit, OnDestroy {
private loginStrategyService: LoginStrategyServiceAbstraction,
private messagingService: MessagingService,
private ngZone: NgZone,
+ private passwordGenerationService: PasswordGenerationServiceAbstraction,
private passwordStrengthService: PasswordStrengthServiceAbstraction,
private platformUtilsService: PlatformUtilsService,
private policyService: InternalPolicyService,
private registerRouteService: RegisterRouteService,
private router: Router,
+ private ssoLoginService: SsoLoginServiceAbstraction,
private syncService: SyncService,
private toastService: ToastService,
) {
@@ -279,6 +285,53 @@ export class LoginComponent implements OnInit, OnDestroy {
}
}
+ protected async launchSsoBrowser() {
+ // Save off email for SSO
+ await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
+
+ // Generate necessary sso params
+ const passwordOptions: any = {
+ type: "password",
+ length: 64,
+ uppercase: true,
+ lowercase: true,
+ numbers: true,
+ special: false,
+ };
+
+ const state =
+ (await this.passwordGenerationService.generatePassword(passwordOptions)) +
+ ":clientId=browser";
+ const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
+ const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, "sha256");
+ const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
+
+ await this.ssoLoginService.setCodeVerifier(codeVerifier);
+ await this.ssoLoginService.setSsoState(state);
+
+ const env = await firstValueFrom(this.environmentService.environment$);
+ let url = env.getWebVaultUrl();
+ if (url == null) {
+ url = "https://vault.bitwarden.com";
+ }
+
+ const redirectUri = url + "/sso-connector.html";
+
+ // Launch browser
+ this.platformUtilsService.launchUri(
+ url +
+ "/#/sso?clientId=browser" +
+ "&redirectUri=" +
+ encodeURIComponent(redirectUri) +
+ "&state=" +
+ state +
+ "&codeChallenge=" +
+ codeChallenge +
+ "&email=" +
+ encodeURIComponent(this.formGroup.controls.email.value),
+ );
+ }
+
protected async goAfterLogIn(userId: UserId): Promise {
const masterPassword = this.formGroup.value.masterPassword;