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'
}
]
}
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.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
get-token.js
file nameconst 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);
});
npm install axios base-64
node get-token.js
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.