javascriptangulartypescriptasp.net-corebraintree

Error: Uncaught (in promise): BraintreeError: options.authorization is required when instantiating a client


I am actually trying to implement braintree using Angular with asp.net core. But i am facing an issue, I don't understand how to solve it. I am follwing this article. I am using version 14 of angular. I have doing exactly the same as mentioned article. I don't know which authorization it is demanding. when i run the application, in the braintree UI, I failed to input Card Number ,Expiration date,CVV maybe for this error. here is my code:-

app.component.ts

import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import * as braintree from 'braintree-web';

@Component({
  selector: 'app-paypal',
  templateUrl: './paypal.component.html',
  styleUrls: ['./paypal.component.css']
})
export class PaypalComponent implements OnInit {

  CToken: any;
  hostedFieldsInstance: braintree.HostedFields;
  cardholdersName: string;
  

  constructor(private http: HttpClient) { }

  ngOnInit(): void {
    this.getToken();
    this.createBraintreeUI();
    
  }

    getToken() {
    this.http.get('https://localhost:5001/api/paypal').subscribe({
      next: response => this.CToken = response,
      error: error => console.log(error)
    })
    console.log(this.CToken);
  }



  createBraintreeUI() {
    braintree.client.create({
      authorization: this.CToken
    }).then((clientInstance) => {
      braintree.hostedFields.create({
        client: clientInstance,
        styles: {
          // Override styles for the hosted fields
        },
        

       
        fields: {
          number: {
            selector: '#card-number',
            placeholder: '1111 1111 1111 1111'
          },
          cvv: {
            selector: '#cvv',
            placeholder: '111'
          },
          expirationDate: {
            selector: '#expiration-date',
            placeholder: 'MM/YY'
          }
        }
      }).then((hostedFieldsInstance) => {

        this.hostedFieldsInstance = hostedFieldsInstance;

        hostedFieldsInstance.on('focus', (event) => {
          const field = event.fields[event.emittedBy];
        });

        hostedFieldsInstance.on('blur', (event) => {
          const field = event.fields[event.emittedBy];
        });

        hostedFieldsInstance.on('empty', (event) => {
          const field = event.fields[event.emittedBy];
        });

        hostedFieldsInstance.on('validityChange', (event) => {
          const field = event.fields[event.emittedBy];
          if (field.isPotentiallyValid) { 
            
          } else {
           
          }
          
        });
      });
    });
  }


   // Tokenize the collected details so that they can be sent to your server
   tokenizeUserDetails() {
    this.hostedFieldsInstance.tokenize({cardholderName: this.cardholdersName}).then((payload) => {
      console.log(payload);
     console.log("Bro! this is payload!!!"+payload.nonce);
      // submit payload.nonce to the server from here
    }).catch((error) => {
      console.log(error);
      // perform custom validation here or log errors
    });
  }

 


}

app.compoment.html

 <form id="cardForm">
    <div class="panel">
      <header class="panel__header">
        <h1>Card Payment</h1>
      </header>
      <div class="panel__content">
        <div class="textfield--float-label">
          <!-- Begin hosted fields section -->
          <label class="hosted-field--label" for="card-number"><span class="icon">
           <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"/></svg></span> Card Number 
          </label>
          <div id="card-number" class="hosted-field"></div>
          <!-- End hosted fields section -->
        </div>
          <div class="custom-name">
            <label class="hosted-field--label" for="cardholder-name" name="cardholderName">
            <span class="icon">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1S9.9 9.16 9.9 8s.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1H5.9V17c0-.64 3.13-2.1 6.1-2.1M12 4C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
              </span>
              Cardholder's Name</label>
      <input type="text" placeholder="e.g. JOHN DOE" class="name-custom-input" [(ngModel)]="cardholdersName" name="cardholderName"/>
    </div>
        <div class="textfield--float-label">
          <!-- Begin hosted fields section -->
          <label class="hosted-field--label" for="expiration-date">
             <span class="icon">
            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path d="M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z"/></svg>
           </span>
            Expiration Date</label>
          <div id="expiration-date" class="hosted-field"></div>
          <!-- End hosted fields section -->
        </div>
        <div class="textfield--float-label">
          <!-- Begin hosted fields section -->
          <label class="hosted-field--label" for="cvv">
            <span class="icon">
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/></svg>
              </span>
              CVV</label>
          <div id="cvv" class="hosted-field"></div>
          <!-- End hosted fields section -->
        </div>
      </div>
      <footer class="panel__footer">
        <input type="button" value="Pay" (click)="tokenizeUserDetails();" class="pay-button"/>
      </footer>
    </div>
  
  </form> 

Backend

 [Produces("application/json")]
...

        [HttpGet]
        public async Task<string> client_token()
        {
            var gateway =  _braintreeService.GetGateway();
            var clientToken =  gateway.ClientToken.generate();
            return  clientToken;
        }

here is my error in console

ERROR Error: Uncaught (in promise): BraintreeError: options.authorization is required when instantiating a client.
    Angular 16
    4431 main.ts:11
    Webpack 7
        __webpack_require__
        __webpack_exec__
        <anonymous>
        O
        <anonymous>
        webpackJsonpCallback
        <anonymous>
core.js:6498
    Angular 3
    RxJS 5
    Angular 18
    4431 main.ts:11
    Webpack 7

enter image description here

I am a beginner. how to resolve this issue. or any alternative implementation? please help.


Solution

  • Check order of asynchronous requests.

    It appears you're not including your Braintree token in your request.

    This is likely happening because you're making one asynchronous request before another completes.

    A simple way to fix this would be to move the call to this.createBraintreeUI() inside the response to you token request. That way you would only make the second request after the first completes.

    Something like this:

      ngOnInit(): void {
        this.getToken();    
      }
    
      getToken() {
        this.http.get('https://localhost:5001/api/paypal').subscribe({
          next: response => { 
            console.log(this.CToken);
            this.CToken = response;
            this.createBraintreeUI(); 
          },
          error: error => console.log(error)
        })
    
      }
    

    There may be more issues, as this is a complex integration with Braintree, but if you check that console.log() statement you have and it's showing your token, and the token looks correct, then you're on the right path.

    (For instance, you might have another problem where you can't pass authorization: this.CToken there in the first line of your this.createBraintreeUI() function. You might have to set authorization to a property of this.CToken. So look at the console.log statement showing your token and see if it looks correct. )