Paypal - "ID token context does not have required scope" error when trying to render paypal button using saved payment info - paypal

I have been trying to save customer payment details on a site, so that if a customer is logged in they can pay with a single click, instead of having to log in to paypal. To do so I have been following the official paypal guide: https://developer.paypal.com/beta/vault/during-purchase/js-sdk/paypal/
I was able to successfully save payment details. The problem is that when I try to use the saved customer_id to use those saved payment details, I get the following error: "Error: cannot get vault - ID token context does not have required scope".
What I did was the following:
Generate an id_token and access_token by sending a request to https://api-m.sandbox.paypal.com/v1/oauth2/token and specifying response_type=id_token
When rendering the paypal button, pass the generated id_token to the script tags data-user-id-token attribute.
I click the paypal button on the website. This sends a request to my backend server which generates an order by sending a request to https://api-m.sandbox.paypal.com/v2/checkout/orders/. When generating the order I use the generated access_token as a Bearer token in the "Authorization" header, as well as pass the following payment_source.paypal configuration:
"paypal": {
"attributes": {
"vault": {
"store_in_vault": "ON_SUCCESS",
"usage_type": "MERCHANT",
"customer_type": "CONSUMER"
}
}
I get an order id in the response. I pass this order id back to the client side, where the paypal sdk initates a payment flow using this id.
I finish the payment flow, and on success call my server's captureOrder endpoint. This calls https://api-m.sandbox.paypal.com/v2/checkout/orders/$id/capture, where $id is the orderID used before. I also pass the Beares access_token generated in the first step. This request returns a response containing a generated user ID that looks something like this: 560837847
I send another request to https://api-m.sandbox.paypal.com/v1/oauth2/token, this time passing a target_customer_id parameter in the request's body. The value of the parameter is the customerId generated in the 5th step.
I render the page with the paypal button again, this time passing the new id_token to the script tags data-user-id-token attribute.
The error "Error: cannot get vault - ID token context does not have required scope" appears in the developer tools console.
I have turned on "Accept payments" on the Paypal developer console as well as Vault functionality:
The id_token generated in the 6th step has the following scopes:
https://uri.paypal.com/services/invoicing
https://uri.paypal.com/services/vault/payment-tokens/read
https://uri.paypal.com/services/disputes/read-buyer
https://uri.paypal.com/services/payments/realtimepayment
https://uri.paypal.com/services/disputes/update-seller
openid
https://uri.paypal.com/services/payments/payment/authcapture
https://uri.paypal.com/services/disputes/read-seller
Braintree:Vault
https://uri.paypal.com/services/payments/refund
https://api.paypal.com/v1/vault/credit-card
https://api.paypal.com/v1/payments/.*
https://uri.paypal.com/payments/payouts
https://uri.paypal.com/services/vault/payment-tokens/readwrite
https://api.paypal.com/v1/vault/credit-card/.*
https://uri.paypal.com/services/shipping/trackers/readwrite
https://uri.paypal.com/services/subscriptions
https://uri.paypal.com/services/applications/webhooks
I cannot find any information online about what else I should do to make this work.

Related

Seller PayPal account not receiving payment on REST API payment

I'm trying to implement server side paypal rest api in django rest framework,i have to say paypal's documentation is not helping matters at all,but so far i have been able to successfully pay money from a sandbox buyer account by first getting access token:
def generate_access_token():
url="https://api-m.sandbox.paypal.com/v1/oauth2/token"
headers={
'Content-Type': 'application/json'
}
auth=(settings.PAYPAL_CLIENT_ID,settings.PAYPAL_SECRET_KEY)
data={
"grant_type":"client_credentials"
}
response=requests.post(url,headers=headers,auth=auth,data=data)
token=response.json()['access_token']
return token
Then i create an order for the buyer to pay:
def pay_for_order(token,price,order_id):
url="https://api-m.sandbox.paypal.com/v2/checkout/orders"
headers={
'Content-Type': 'application/json',
'Authorization':f'Bearer {token}'
}
data={
'intent':'CAPTURE',
'application_context':{
'return_url':f'http://127.0.0.1:8000/payment/confirm-payment/1/{token}/',
'cancel_url':f'http://127.0.0.1:8000/payment/confirm-payment/2/{token}/'
},
'purchase_units':[
{
"reference_id":f'{order_id}',
"amount":{
'currency_code':'USD',
'value':f'{price}'
}
}
]
}
response=requests.post(url,headers=headers,data=json.dumps(data))
print(response.json())
response_json=response.json()
return response_json
then the order capture is called in the endpoint in the return url when payment is successful like this:
def final_payment_verification(token,paypal_token):
url=f'https://api.sandbox.paypal.com/v2/checkout/orders/{paypal_token}/capture'
headers={
'Content-Type': 'application/json',
'Authorization':f'Bearer {token}'
}
response=requests.post(url,headers=headers)
print(response.json())
response_json=response.json()
return response_json
but the major issue now is that the seller doesn't get credited my intuition was that generating access token with seller's client id and secret key already stands as identification for whoever the buyer's payment is going to but unfortunately only the buyer get's debited,i checked the whole order api on paypal docs but couldn't find fields that require buyers or recipient info so paypal can pay to them,all solutions online are for client side checkout and paypal docs are not helping matters at all,there are even some read more pages that lead to totally diffrent unrelated content and every resource online mostly use the v1 version other than the latest v2,I would really like to know what i'm doing wrong.
The code is in sandbox mode, so you must be using a sandbox client ID and secret. Are you looking in the seller sandbox account (open a separate tab to log in to www.sandbox.paypal.com with it) that corresponds to the REST APP client ID and secret you are using?
If you still have issues, log the entire capture API response body and include it in your question.

INVALID_RESOURCE_ID when Authorization.Capture is called on an authorized payment using sandbox account

I am using PayPal.1.6.0\lib\net45\PayPal.dll
I created a payment with authorize intent and have the successfully authorized authID (Payment.Cart) and the PayPal.APi.Payment.id.
When I try to call the Authorization.Capture(apiContext, Capture) with the authID, I get
{
"name":"INVALID_RESOURCE_ID",
"message":"The requested resource ID was not found",
"information_link":"https://developer.paypal.com/webapps/developer/docs/api/#INVALID_RESOURCE_ID",
"debug_id":"d73f6a0c1b8bc"
}
I tested this using my sandbox account.
Trying the link gets me a 'page not found error'. Any clues?
I realized that i was looking at the wrong 'authorization code'. It is not the ((Payment)executedPayment).cart as posted in my original question but ((Payment)executedPayment).transactions.FirstOrDefault().authorization.id
I was able to use the correct authCode and am able to capture my authorization. executedPayment is the return value from Payment.Execute method.

get conversations of FB page via open graph api

I've registered an Facebook-App and created a token with all permissions I need. Among them
manage_pages
read_mailbox
read_page_mailbox
Now I want to use the Facebook open graph API to read some data from my own FB-page. I want to read the private messages that the page received and that I sent to some of the fans on my pages behalf.
I know I can get all information by sending a http-request like this:
https://graph.facebook.com/{page-id}/{object}?access_token={token}
where {something} are placeholders for actual values. To give an working example, I can read the postings that appeared on my page by sending this request:
https://graph.facebook.com/141928949155955/posts?access_token={my secret token}
As I said, this works fine, since more than two years. (I just need to update the token from time to time)
But now I want to read the private conversations between the page and it's fans. I want to extract all conversations and insert them into a spreadsheet. I want to do it once, and maybe in 1 or 2 years again. I could extract them manually from the browser window by copy and paste for each conversation, but since there are so many conversations I think it costs less time to let a program do it for me.
If I understand Facebooks Documentation correct, then the keyword that I must use must be conversations. But I get this:
https://graph.facebook.com/141928949155955/conversations?access_token={secret token}
{
"error": {
"message": "(#210) Subject must be a page.",
"type": "OAuthException",
"code": 210
}
}
But 141928949155955 is a page. I don't know what I'm doing wrong. What is the correct request that I must send to receive a pages private conversations?
EDIT (June 16th):
I can read my personal conversations with this request:
https://graph.facebook.com/me/conversations?access_token={secret token}
But I don't want to read the conversations that I made as a person. I need those of one of my pages.
I found the solution for my problem. (Thanks kush, your answer helped a lot, but I want to add some more information)
My problem was that I misunderstood the error message "Subject must be a page." I thought that "Subject" refers to a part in the query string. But it refers to the token! A message like "Token must be a Page Access Token" would have saved me WEEKS of needless searching over a period of more than two years! How can you use a term like "Subject" when you nowhere define what "Subject" is?
So it was not the query string that was wrong. It was the type of the token!
Now here is the complete procedure to solve the problem (get a Page Access Token)
SOLUTION
Step 1
Get a User Access Token for your App that you can use later to get a Page Access Token
1.1 Go to Graph API Explorer https://developers.facebook.com/tools/explorer/
1.2 Select your App from the "Application:" drop down menu.
1.3 Click "Get Access Token".
1.4 From the tab "Extended Permissions" select "manage_pages".
Additionally select all permissions you need for the Page Access Token. (Although now you don't create a Page Access Token, just a User Access Token)
1.5 Click "Get Access Token".
1.6 Grant the permissions by clicking "OK".
In the field "Access Token:" you find now a Token that is an User Access Token. It is not a Page Access Token! This Token has all permissions you need to manage your page (including the permission "manage_pages"), but you can't use it to manage pages since it is the wrong type of token. You need this token only for one reason: To create a new token.
Step 2
Use the User Access Token you just got to create a Page Access Token
2.1 Enter "me/accounts" in the query field
2.2 Click "Submit"
You get a list of your pages, each with an "access_token" (which is now a Page Access Token). Each of this tokens did inherit the permissions from the User Access Token you used when you called "me/accounts".
This Page Access Token expires after one hour.
supplement
If you want a Page Access Token that never expires, do it this way:
A.1 Go to https://developers.facebook.com
A.2 From the drop down menu "Apps" select the App you want to use.
A.3 Click on "show" in the field "App Secret" (you need to enter your Facebook Password)
A.4 Open a new tab in your browser and there execute steps 1.1 to 1.6 from above to generate a short-lived User Access Token
A.5 Open a third Tab in your browser and there enter this string into the address field of your browser:
https://graph.facebook.com/v2.0/oauth/access_token?grant_type=fb_exchange_token&client_id={app-id}&client_secret={app-secret}&fb_exchange_token={short-lived-token} (do not press enter!) If this strings disappears when switching from one browser tab to another use any text editor to assemble the string and copy it later into the address field.
A.6 In this string replace {app-id} and {app-secret} by the values from the browser tab that still shows your Apps data.
A.7 Replace {short-lived-token} with the User Access Token you find in the field "Access Token:" from the Graph API Explorer.
(After this step there are no more curly brackets in the address string)
A.8 send this request (press Enter now)
Your browser window now shows a String with the fields "access_token" and "expires", separated by an ampersand ("&") which is not part of the token. This Token is a long lived User Access Token that will expire in two month.
A.9 Execute Steps 2.1 and 2.2 using the "access_token" from step A.8
The result is a Page Access Tokes with all permissions you selected in Step 1.4 and that never will expire.
Good luck!
Using page access token should help since you are reading from the page ..
Graph api node: GET me/accounts
me/accounts would give you the pages you are admin for and use access token coming in the page info dictionary.
you should get the following data from me/accounts
{
"data": [
{
"category": "Product/service",
"name": "Sample Page",
"access_token": "{page-access-token}",
"id": "1234567890",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
}
Use page-access-token to access data from page as the page admin and thou shall receive data :) let me know if this works :)
A successful authorization would return an access token to your app, which you can then use to perform actions to the Facebook API. The error message displayed means you do not have a valid access token which means you probably did not authenticate the app correctly. I would put some logging on the onFacebookError and onError methods to see what the problem is.
Request Permission At Login time So Its Authentication Error
Permission List
https://developers.facebook.com/docs/facebook-login/access-tokens/
Set Permission Reference
https://developers.facebook.com/docs/android/login-with-facebook#permissions

Validating the user of an access_token

In the Facebook dev article Manually Building a Login Flow, there is a section entitled "Confirming Identity". It mentions that you need to validate codes and tokens that you receive from them via your redirect_uri.
My question: Since you don't know anything about the user that just logged in, how do you validate that the user_id that you see in the response from the token inspection endpoint is correct?
The article says:
As a result, your app should confirm that the person using the app is the same person that you have response data for before generating an access token for them.
But, how can you actually do that? Are we expected to show publicly available info about that user_id back to the user with a UI that asks "Is this you?". I haven't seen any apps/sites that do that, so I'm assuming that this isn't practically done.
Am I missing something?
You can use FB.getLoginStatus to retrieve information about the logged in user. It returns a response object for the user. If the user has authenticated your application, the response object will look like this:
{
status: 'connected',
authResponse: {
accessToken: '...',
expiresIn:'...',
signedRequest:'...',
userID:'...'
}
}
You can use the UserId returned in this object to verify the user's identity.

Can I get payer_id with "Login with Paypal"?

I'm integrating Log In with PayPal - JavaScript Button.
https://developer.paypal.com/webapps/developer/docs/integration/direct/log-in-with-paypal/js_button/
I need "payer_id" of the user who logged in with paypal.
But it's NOT included in a response.
A response of "4. Get User's PayPal Profile Data" in above integration guide is like this :
{
"family_name":"Ito",
"name":"Gen Ito",
"account_type":"BUSINESS",
"given_name":"Gen",
"user_id":"ttps://www.paypal.com/webapps/auth/identity/user/xxxxxxxxxxxxxxxxx",
"verified_account":"true",
"language":"ja_JP",
"zoneinfo":"Asia/Tokyo",
"locale":"ja_JP",
"email":"xxx#xxx",
"account_creation_date":"2011-11-18",
"birthday":"1982-08-02",
"age_range":"26-30"
}
"payer_id" is listed in below, so I thought payer_id is available.
https://developer.paypal.com/webapps/developer/docs/api/#get-user-information
Can I get payer_id with "Login with Paypal" ?
Then should I use another/other request ?
you need to submit a support ticket at www.paypal.com/mts and request access to this attribute.