Issue
I have spent days trying to figure out the pieces to get a working payment portal on my website. I am not selling products directly from the website, but I do want to accept payments for invoices issues from my Paypal business account through my website. In order to do that, I need to be able to retrieve a list of invoices associated with their email address so they can select one and pay for it, which I can do through the Invoiced API. In order to do that I need to make a call to the Authentication API to get an access token.
The Authentication API documentation gives me instructions for making the request via cURL
and Postman
, neither of which I've used before. I found a site that could convert the cURL
request into a fetch
request, which gave me the following:
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"
})
I figured the string in the Authorization
property was based on the original -u "<CLIENT_ID>:<CLIENT_SECRET>"
cURL flag from the API's documentation, so I did a little further digging and figured, based on the answers to this question that I could change that to the Authorization
property to 'Bearer ' + CLIENT_ID:CLIENT_SECRET
, so pulling the Client ID and Client Secret from the env variables and storing them into clientID
and secret
respectively (on the server side, of course), I then tries using 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)
and it printed out the following:
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'
}
]
}
Solution
Using axios
instead of fetch
You needs to encode to Base64 format
the Client id
and Client Secret
part.
it help to little bit of protection instead direct text.
base64 encoding for authorization
base64.encode(client_id + ":" + client_secret)
Authorization: Basic
Base64 result
Example:
Client id
: bHRpY3VsdHwuY29tcH
Client Secret
: pQaE-ceDi3nFz
encode base 64(bHRpY3VsdHwuY29tcH:
pQaE-ceDi3nFz) -> YkhScFkzVnNkSHd1WTI5dGNIOnBRYUUtY2VEaTNuRno=
Authorization
: Basic YkhScFkzVnNkSHd1WTI5dGNIOnBRYUUtY2VEaTNuRno=
detail information in here
Full code - save as get-token.js
file name
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);
});
Install & run it
npm install axios base-64
node get-token.js
Result
You can verify by Postman
Detail information in here
If you have a still some error, Check your permission
& App feature options
on developer portal
And change a debugging code - line 22~23, line 32~33 You can see the scope and other information.
Answered By - Bench Vue Answer Checked By - Senaida (WPSolving Volunteer)