What is the process for making a fetch request to Paypal's Oath API version 2?

After spending days working on setting up a functional payment portal on my website, I have hit a roadblock. My website does not directly sell products, but I do need to accept payments for invoices generated from my Paypal business account. To achieve this, I am looking to integrate an invoicing API that will allow users to view and pay their invoices through my website. However, to access this functionality, I first need to retrieve a list of invoices associated with the user's email address by utilizing the Invoiced API. To do this, I have to make a request to the Authentication API to obtain an access token.

The documentation for the Authentication API provides instructions for making the request using cURL and Postman. Although I am unfamiliar with both, I found a tool that converted the cURL request into a fetch request, resulting in the following code snippet:

fetch("https://api-m.sandbox.paypal.com/v1/oauth2/token", {
  body: "grant_type=client_credentials",
  headers: {
    Authorization: "Basic PENMSUVOVF9JRD46PENMSUVOVF9TRUNSRVQ+",
    "Content-Type": "application/x-www-form-urlencoded"
  },
  method: "POST"
})

Realizing that the Authorization property string is derived from the original cURL flag format, I further investigated and discovered a way to modify it by appending the Client ID and Client Secret as 'Bearer ' + CLIENT_ID:CLIENT_SECRET. After extracting the Client ID and Secret from environment variables and storing them as clientID and secret respectively on the server side, I attempted to use the following code:

    const token = await fetch("https://api-m.sandbox.paypal.com/v1/oauth2/token", {
        body: "grant_type=client_credentials",
        headers: {
            Authorization: `Bearer ${clientID}:${secret}`,
            "Content-Type": "application/x-www-form-urlencoded"
        },
        method: "POST"
    })

    console.log(await token)

Upon execution, the following output was displayed:

Response {
  size: 0,
  timeout: 0,
  [Symbol(Body internals)]: {
    body: PassThrough {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      [Symbol(kCapture)]: false,
      [Symbol(kCallback)]: null
    },
    disturbed: false,
    error: null
  },
  [Symbol(Response internals)]: {
    url: 'https://api-m.sandbox.paypal.com/v1/oauth2/token',
    status: 401,
    statusText: 'Unauthorized',
    headers: Headers { [Symbol(map)]: [Object: null prototype] },
    counter: 0
  }
}
{
  name: 'AUTHENTICATION_FAILURE',
  message: 'Authentication failed due to invalid authentication credentials or a missing Authorization header.',
  links: [
    {
      href: 'https://developer.paypal.com/docs/api/overview/#error',
      rel: 'information_link'
    }
  ]
}

Answer №1

Instead of using the fetch function, consider using axios for your API requests.

For added security, it is recommended to encode the Client id and Client Secret in Base64 format rather than using plain text.

Authorization with Base64 Encoding

base64.encode(client_id + ":" + client_secret)

Authorization: Basic Base64 result

Example:

Client id: bHRpY3VsdHwuY29tcH

Client Secret: pQaE-ceDi3nFz

Encoding in Base64(bHRpY3VsdHwuY29tcH:pQaE-ceDi3nFz) -> YkhScFkzVnNkSHd1WTI5dGNIOnBRYUUtY2VEaTNuRno=

Authorization:

Basic YkhScFkzVnNkSHd1WTI5dGNIOnBRYUUtY2VEaTNuRno=

For more details, visit this link

Complete code - save as get-token.js file

const axios = require("axios")
const base64 = require('base-64');

const getToken = async () => {
    try {
        const client_id = 'Aeb...your-client-id...s-q'
        const client_secret = 'EDM...your-secret...ZXv'

        const response = await axios.post('https://api-m.sandbox.paypal.com/v1/oauth2/token',
            new URLSearchParams({
                'grant_type': 'client_credentials'
            }),
            {
                headers:
                {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Authorization': 'Basic ' + base64.encode(client_id + ":" + client_secret)
                }
            })
        return Promise.resolve(response.data.access_token);
        // for debugging
        // return Promise.resolve(response.data);

    } catch (error) {
        return Promise.reject(error);
    }
}

getToken()
    .then(token => {
        console.log("access token: " + token)
        // for debugging
        // console.log("response: " + JSON.stringify(token, null, 4))
    })
    .catch(error => {
        console.log(error.message);
    });

Installation & Execution

npm install axios base-64
node get-token.js

Output

https://i.sstatic.net/rSX4N.png

Verification using Postman

https://i.sstatic.net/Zo83U.png https://i.sstatic.net/PIgn1.png

For more information, check this link

If you encounter any errors, ensure your permissions & App feature options on the developer portal are set correctly.

https://i.sstatic.net/3S9U3.png

https://i.sstatic.net/E9g3W.png To view additional information, modify the debugging code - line 22~23, line 32~33 This will provide insight into the scope and other details.

https://i.sstatic.net/qt4v5.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

There was a dependency resolution error encountered when resolving the following: [email protected] 12:15:56 AM: npm ERR! Discovered: [email protected] . The Netlify deploy log is provided below for reference

5:27:42 PM: Installing npm packages using npm version 8.19.3 5:27:44 PM: npm ERR! code ERESOLVE 5:27:44 PM: npm ERR! ERESOLVE could not resolve 5:27:44 PM: npm ERR! 5:27:44 PM: npm ERR! While resolving: [email protected] 5:27:44 PM: npm ERR! Foun ...

Utilizing Aramex API in React Native: A Step-by-Step Guide

Currently, I am tackling an eCommerce venture that requires the utilization of Aramex APIs for shipping and other functionalities. Since my project is being developed in React Native, I am seeking guidance on how to integrate Aramex APIs into this framewo ...

Problem with jQuery's UI autocomplete functionality

Implementing jQ UI Autocomplete with multiple values Below is how my function is structured: mailto_input.bind( "keydown", function( event ) { if ( event.keyCode === $.ui.keyCode.TAB && $( this ).data( "autocomplete" ).menu.active ) { ...

Is there a way to have the submit button show the uploaded file on the same page, without redirecting to a new

My code seems to be malfunctioning and I suspect it's due to some errors. I'm attempting to have the submit button display an image of a molecule using JSmol. Can anyone lend a hand with this? <script> var Molecule = { width: 550, ...

Issue with converting string to Date object using Safari browser

I need to generate a JavaScript date object from a specific string format. String format: yyyy,mm,dd Here is my code snippet: var oDate = new Date('2013,10,07'); console.log(oDate); While Chrome, IE, and FF display the correct date, Safari s ...

How can I convert the date format from ngbDatepicker to a string in the onSubmit() function of a form

I'm facing an issue with converting the date format from ngbDatepicker to a string before sending the data to my backend API. The API only accepts dates in string format, so I attempted to convert it using submittedData.MaturityDate.toString(); and su ...

Navigating AngularJS with multiple external files and folders

Recently dove into Angular and hit a roadblock with routing. I followed the setup instructions, but for some reason it's not functioning as expected. index.html: <!DOCTYPE html> <html lang="en> <head> <meta charset="utf-8> ...

Tips for determining if an array includes a specific item

I am seeking to limit the keys that are allowed to be pressed. $('.txtComments').keydown(function (event) { var keys = new Array(); keys[0] = "8"; keys[1] = "46"; keys[2] = "37" keys[3] = "39" if(!(....)) //Verify if the keyCode cor ...

jQuery still not running despite using .ready

I have been attempting to run some jQuery code on my HTML page. After doing some research, I learned that using .ready may be necessary to ensure the DOM is fully loaded before executing the script. Despite this, I am still having trouble getting the scrip ...

bespoke session with Next.js using Next-Auth

I encountered an issue while migrating my JS file to TSX. What I am trying to do is sign in with credentials and customize the session user to my user data. // api/auth/[...nextauth].js import NextAuth from "next-auth"; import Providers from &qu ...

The upload directory fails to include the folder name when sending a file

After experimenting with the new directory upload feature, I encountered an issue where the server request did not preserve the exact folder structure as expected. Here is the HTML code snippet: <form action="http://localhost:3000/" method="post" enct ...

AngularJS directive and customized markup/function

Here is the code snippet I am currently working with: <body ng-controller="testController"> <div test-directive transform="transform()"> </div> <script type="text/ng-template" id="testDirective.html"> <div& ...

The settimeout function does not seem to function properly within the context of

Currently, I am facing an issue with implementing block UI for blocking a specific div when a button is clicked. The problem I am encountering is that even though I want the blocked div to be unblocked after a certain delay, it remains permanently blocked ...

Storing executable scripts in HTML5 LocalStorage allows for the dynamic creation

As I work on a hybrid app with its own local HTML and JS files, there are times when I need to load additional small executable JS scripts and CSS from the server. Currently, I achieve this by using $.getScript, which has been working well. In order to ma ...

Explore vue3 components using vue-test-library and universal components

I started creating unit tests for a production app using jest, @testing-library/vue, and supporting libraries. The first test I created is as follows: import vue from "vue"; import { render } from "@testing-library/vue"; import LibBtn f ...

Trigger the activation of an input field upon clicking an image labeled "edit"

I am currently developing a website where administrators have access to a dashboard page that displays a list of users. I am looking to implement a feature that allows admins to change the roles of other users directly from the same table row. Below is th ...

Real-time JQuery search with instant results

While utilizing a custom script to display search results on the page, I encountered an issue when typing long sentences. Each request goes to the server, resulting in delayed responses that stack up and cause the div to change quickly. This is not the des ...

Stuck with the same icon even after a successful AJAX call

I am currently working on implementing a 'add to my list' function in my web app. The goal is to change the color of an icon when a user clicks on it, after sending the necessary data to the server. Despite successfully sending the data to the s ...

The HiddenField is returning empty when accessed in the code behind section

In my gridview, the information is entered through textboxes and saved to the grid upon clicking a save button. One of these textboxes triggers a menu, from which the user selects a creditor whose ID is then saved in a HiddenField. <td class="tblAddDet ...

Changing the Position of HTML Scripts in React

I am facing an issue where I need to relocate an external script within a specific section of my page. However, I am unable to access the CSS attributes associated with this item. It seems that it is displayed as an iFrame, making it difficult to modify th ...