Repository: hashicorp/vault
File: ui/app/components/auth/form/base.ts (TypeScript)

Code before:
  @action
  onSubmit(event: HTMLElementEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.target as HTMLFormElement);
    const data = this.parseFormData(formData);
    this.login.unlinked().perform(data);
  }

  login = task(
    waitFor(async (formData) => {
      try {
        const authResponse = await this.auth.authenticate({
          clusterId: this.args.cluster.id,
          backend: this.args.authType,
          data: formData,
          selectedAuth: this.args.authType,
        });

        this.handleAuthResponse(authResponse);
      } catch (error) {
        this.onError(error as Error);
      }
    })
  );

  handleAuthResponse(authResponse: AuthData) {
    // calls onAuthResponse in parent auth/page.js component
    this.args.onSuccess(authResponse);
  }

  onError(error: Error | string) {
    if (!this.auth.mfaErrors) {
      const errorMessage = `Authentication failed: ${this.auth.handleError(error)}`;
      this.args.onError(errorMessage);
    }
  }

  parseFormData(formData: FormData) {
    const data: Record<string, FormDataEntryValue | null> = {};

    // iterate over method specific fields
    for (const field of POSSIBLE_FIELDS) {
      const value = formData.get(field);
      if (value) {
        data[field] = value;
      }
    }

    // path is supported by all auth methods except token
    if (this.args.authType !== 'token') {
      // strip leading or trailing slashes for consistency.

Review comment (suggestion):
passing to support mfa validation for standard methods, but this is going to check a bit when everything is wired up because the end goal is for mfa validation to be handled the same for all methods

Code after:
  @action
  onSubmit(event: HTMLElementEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.target as HTMLFormElement);
    const data = this.parseFormData(formData);
    this.login.unlinked().perform(data);
  }

  login = task(
    waitFor(async (formData) => {
      try {
        const authResponse = await this.auth.authenticate({
          clusterId: this.args.cluster.id,
          backend: this.args.authType,
          data: formData,
          selectedAuth: this.args.authType,
        });

        this.handleAuthResponse(authResponse, this.args.authType, formData);
      } catch (error) {
        this.onError(error as Error);
      }
    })
  );

  handleAuthResponse(authResponse: AuthData, authType: string, formData?: object) {
    // calls onAuthResponse in parent auth/page.js component
    this.args.onSuccess(authResponse, authType, formData);
  }

  onError(error: Error | string) {
    if (!this.auth.mfaErrors) {
      const errorMessage = `Authentication failed: ${this.auth.handleError(error)}`;
      this.args.onError(errorMessage);
    }
  }

  parseFormData(formData: FormData) {
    const data: Record<string, FormDataEntryValue | null> = {};

    // iterate over method specific fields
    for (const field of POSSIBLE_FIELDS) {
      const value = formData.get(field);
      if (value) {
        data[field] = value;
      }
    }

    // path is supported by all auth methods except token
    if (this.args.authType !== 'token') {
      // strip leading or trailing slashes for consistency.