Code Monkey home page Code Monkey logo

paypal-retail-node's Introduction

Authentication for the Retail SDK

Build Status Join the chat at https://gitter.im/paypal/retail-sdk

TL;DR: You need to use your client ID and secret from developer.paypal.com to get a token to call InitializeMerchant within the SDK. You can use our modules in your own server (node.js express/Kraken, ruby, Java, .Net, ...), or use one of our prebuilt Docker containers or Heroku builds (most of this is aspirational right now). You can do this for free on Heroku and Amazon EC2, including SSL if you use something like CloudFlare.

If you just want to know the gory details of what's happening at the network level, see What's Really Going On Here?.

Once you have your developer account on PayPal.com, to get started with this Node version, deploy it to Heroku by clicking the button below and then configure the environment variables in the Heroku dashboard.

Deploy

Required Environment Variables
APP_SECURE_IDENTIFIERA value [you make up](https://identitysafe.norton.com/password-generator/) and keep secret to protect your PayPal refresh tokens.
Other Environment Variables
SETUP_ENABLEDIf set to true, you can go to /setup/live or /setup/sandbox to generate a token which you can copy into your code. You should turn this off in a 'live' server.
ROOT_URLThe root URL of your new server, e.g. http://something.herokuapp.com. If not set, we will pull it from the first request we see.
PAYPAL_LIVE_CLIENTIDThe PayPal client id for your application in the live environment.
PAYPAL_LIVE_SECRETThe PayPal secret for your application in the live environment.
PAYPAL_SANDBOX_CLIENTIDThe PayPal client id for your application in the sandbox environment
PAYPAL_SANDBOX_SECRETThe PayPal secret for your application in the sandbox environment
APP_REDIRECT_URLFor third party use, *after* PayPal authentication is complete the server will redirect to this URL with the token for InitializeMerchant in the Retail SDK. This is usually some sort of custom URL protocol like 'myappname://paypaltoken' or similar. The URL needs to launch your app and this server will pass it the token.

Usually you're in one of these two situations:

  • First Party - The account I made the PayPal.com developer application with is the only one I ever want to transact with. You will use this server to get a token and then you will put that token in your app.
  • Third Party - I want other merchants to use my application with their own accounts and give me permission to transact for them. You will call this server from your app to get a URL for PayPal Login, then when login completes this server will call APP_REDIRECT_URL as described above.

Click one of those links to get more information about setting up your client app for these situations.

Why can't I just put the id and secret in the app?

PayPal uses OAuth to authenticate an application's ability to transact on behalf of a merchant account. OAuth has three main "sensitive quantities" - the access token, the refresh token and the application secret. The access token is short lived (typically 15 minutes-8 hours) and useful only for a single account. A refresh token is long lived (by spec 10 years, in theory forever, in practice until the owner revokes it) and useful only for a single account. The application secret is permanent for a given application and useful for potentially all accounts.

Generally, it's ok to store the access token on the end-user (e.g. mobile) device. You should still store it securely, not record it in logs, etc, but it's value is short lived. The refresh token should not generally live on the end-user device because it takes away another choke point for you to disable the use of your application in case the device is lost or stolen (because you could just "invalidate" the refresh token for that account and then that device, the next time it came to your server to refresh the token would not get a new access token).

The application secret should never live on the end-user device because anyone who has that can infinitely refresh access tokens given refresh tokens, and can get an access token for YOUR account any time they want. More importantly, anyone holding the application secret can pretend to be your app and have an unsuspecting user give the rogue app an access and refresh token (by logging into PayPal and believing they are granting permission to your app).

So our recommended approach is to use our server modules or containers to create a server that stores your application secret and provides access tokens to your end user devices. Our modules also employ an additional server-only password to return a "modified refresh token" to the end user device which means you don't need a database. When your application needs a new access token, it calls the server module and provides the modified refresh token. The server module combines that with the application secret and calls the PayPal servers to obtain a new access token which it delivers back to the client.

Note that if you needed to make calls OUTSIDE of your application (such as from your backend services), you would need to get the access token/refresh token flow working on your backend services and would then need a database to store relevant user data. Doing so securely is outside of the scope of this document, but each server module readme describes the API, and there's no reason you can't use the same services for your other backend services.

First Party

You can go through the Login With PayPal flow and grant consent to your application just once. The token returned will include the "modified refresh token" that can be baked into your application and shipped. The server modules and containers we provide expose an endpoint for first party token creation (/setup) that can be disabled after you generate the original value. The point of the additional identifier (the APP_SECURE_IDENTIFIER, which you can just make up) is in the case where you have an application compromise or significant bug, you can change this identifier and applications with the old value will stop being able to transact on your behalf. Essentially this identifier is a remote kill switch that you control.

Third Party

Within this scheme there is another big question - do you have your own account system or do you want to use PayPal for all authentication? If you have your own account system, it's very likely you want to use our server modules instead of the standalone containers. In that case you would first authenticate the API caller against your own system, and verify the link between that account and the PayPal account before obtaining access tokens on their behalf. This provides an additional layer of security and control for end user applications making calls for your merchants via your app.

Note: You MUST set the redirect URL of your app on developer.paypal.com to match the server to which you deploy the paypal-retail-node code with the path /returnFromPayPal appended. For example, if you've deployed to http://pph-retail-node.herokuapp.com, the return URL MUST be set to http://pph-retail-node.herokuapp.com/returnFromPayPal

What's Really Going On Here?

Fundamentally, this application manages your client id and client secret in order to generate access tokens on behalf of a merchant (which could be the same account). These access tokens are in turn used by your application to call certain PayPal services on behalf of the merchant. The services which you can call are determined by the scopes you request during token creation. The first time you want to generate an access token for an account, you must send them to PayPal.com to login and consent to the scopes you request. This is accomplished by the /toPayPal endpoint in server.js and in turn the redirect method in this module (which you would use if integrating into your own node.js server). For example, for the client id EXAMPLEID which is registered with developer.paypal.com as having a return url of http://example.com/returnFromPayPal, you would send your merchant to

https://www.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?response_type=code&client_id=EXAMPLEID&scope=openid+email+phone+profile+address+https://uri.paypal.com/services/paypalhere+https://api.paypal.com/v1/payments/.*+https://uri.paypal.com/services/paypalattributes/business&redirect_uri=http%3A%2F%2Fexample.com%2FreturnFromPayPal&state=something_you_need_to_get_back

The redirect_uri must match the URL registered on your application details page on the PayPal developer site EXACTLY. If you need to pass additional information that will be returned to your application post-login, use the state parameter. This implementation uses the state parameter to remember which environment you're trying to login to (e.g. sandbox or live).

Once login is complete, PayPal will send the merchant's browser back to the redirect_uri with an authorization code. The URL would be something like:

http://example.com/returnFromPayPal?state=something_you_need_to_get_back&scope=some_scopes&code=THE_CODE_FROM_PAYPAL

You must take that authorization code and submit it to PayPal, along with your client id and secret, to retrieve the access token and refresh token. This is handled by the /returnFromPayPal endpoint in server.js or the completeAuthentication method in the module. In reality, this is an HTTPS POST to the token endpoint (https://api.paypal.com/v1/identity/openidconnect/tokenservice) with the following URL-encoded form body:

grant_type=authorization_code&code=THE_CODE_FROM_PAYPAL&redirect_uri=http%3A%2F%2Fexample.com%2FreturnFromPayPal

This should return the access and refresh tokens:

{ scope: 'https://uri.paypal.com/services/paypalattributes/business https://uri.paypal.com/services/paypalhere address email openid profile',
  nonce: 'SOME_RANDOM_STUFF',
  access_token: 'A_LONG_CODE',
  token_type: 'Bearer',
  expires_in: 28800,
  refresh_token: 'A_LONGER_CODE'
}

You then make requests using this access token until it expires. Once it expires (which is indicated by an error telling you so), you should call the refresh endpoint (https://api.paypal.com/v1/oauth2/token) with the client id and secret in the Authorization header and the refresh token in the body:

grant_type=refresh_token&refresh_token=A_LONGER_CODE&scope=https://uri.paypal.com/services/paypalattributes/business+phone+https://uri.paypal.com/services/paypalhere+https://api.paypal.com/v1/payments/.*+address+email+openid+profile

And that's all there is to making PayPal API requests using access tokens.

paypal-retail-node's People

Contributors

djmax avatar ppmtscory avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

paypal-retail-node's Issues

Error with Heroku server setup

Hi,

I am integrating the PPH iOS SDK with my app for the first party payment.

I have deployed this mid-tier server with Heroku by clicking the button
image

I have added all required values in Heroku portal:
image

When I click on Open app
image

Click on Setup a Sandbox Account
image

Am I missing anything here?

onErrorWhileSettingAccessTokenToSDK

When I used the sample server from the android paypal here sdk (http://pph-retail-sdk-sample.herokuapp.com/toPayPal/live) everything worked with no problems. Just recently I switched to my own paypal heroku server. The code is exactly the same as before, just different URL and the returnStringCheckParam now starts with my apps name instead of sample server's. Now the issue is that when I initialize the sdk I first get onErrorWhileSettingAccessTokenToSDK dialog and after a second I get onSuccessfulCompletionOfSettingAccessTokenToSDK. Everything works fine after that but I was wondering if you had any clue as to what could cause this error.

Thanks

Error while generating token

I am getting below error while generating token.

internal/crypto/pbkdf2.js:56
throw new ERR_INVALID_ARG_TYPE('digest', ['string', 'null'], digest);
^

TypeError [ERR_INVALID_ARG_TYPE]: The "digest" argument must be one of type string or null. Received type undefined
at check (internal/crypto/pbkdf2.js:56:13)
at Object.pbkdf2 (internal/crypto/pbkdf2.js:25:7)
at encrypt (/home/ubuntu/paypal-retail-node-master/index.js:243:12)
at /home/ubuntu/paypal-retail-node-master/index.js:191:1
at /home/ubuntu/paypal-retail-node-master/node_modules/wreck/lib/index.js:454:20
at finish (/home/ubuntu/paypal-retail-node-master/node_modules/wreck/lib/index.js:296:20)
at wrapped (/home/ubuntu/paypal-retail-node-master/node_modules/hoek/lib/index.js:866:20)
at module.exports.internals.Recorder.onReaderFinish (/home/ubuntu/paypal-retail-node-master/node_modules/wreck/lib/index.js:346:16)
at Object.onceWrapper (events.js:273:13)
at module.exports.internals.Recorder.emit (events.js:187:15)

Return URL

I'm trying to add paypal here sdk to my android app and wanted to use this on heroku as mid-tier server. Now i'm a bit confused as the whole process works and some clarification on the variables would be greatly appreciated. Just to double check I have root url set to the heroku server address (http://example.herokuapp.com), the APP_REDIRECT_URL is set to (appname://ouath). Then I created an app in the paypal developer websites and set the return url to heroku server address (http://example.herokuapp.com).

With these parameters my app tries to login and gets the following error "Relying Party Validation error: redirect_url provided in the request.." I assume that is caused by the redirect and return url matching but I don't exactly understand how that works. I know normally in a webapp the return url would point to a webpage but I how would take work on an android app?

Sample server returns internal server error after granting scope

I'm able to successfully login and grant scope to my app (I am functioning as the merchant and the app developer), however the call to the redirect URL fails with Internal Server Error

2017-01-23T17:41:53.334824+00:00 app[web.1]: SyntaxError: Unexpected token s
2017-01-23T17:41:53.334833+00:00 app[web.1]:     at Object.parse (native)
2017-01-23T17:41:53.334834+00:00 app[web.1]:     at Object.module.exports.completeAuthentication (/app/index.js:160:26)
2017-01-23T17:41:53.334835+00:00 app[web.1]:     at /app/server.js:69:12
2017-01-23T17:41:53.334839+00:00 app[web.1]:     at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
2017-01-23T17:41:53.334840+00:00 app[web.1]:     at next (/app/node_modules/express/lib/router/route.js:131:13)
2017-01-23T17:41:53.334841+00:00 app[web.1]:     at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3)
2017-01-23T17:41:53.334841+00:00 app[web.1]:     at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
2017-01-23T17:41:53.334842+00:00 app[web.1]:     at /app/node_modules/express/lib/router/index.js:277:22
2017-01-23T17:41:53.334843+00:00 app[web.1]:     at Function.process_params (/app/node_modules/express/lib/router/index.js:330:12)
2017-01-23T17:41:53.334844+00:00 app[web.1]:     at next (/app/node_modules/express/lib/router/index.js:271:10)

The url for the call back (with redacted code is)

https://airlift-paypal-auth.herokuapp.com/returnFromPayPal?code=C101.XXXXXX&scope=https%3A%2F%2Furi.paypal.com%2Fservices%2Fpaypalhere%20https%3A%2F%2Fapi.paypal.com%2Fv1%2Fpayments%2F.*%20https%3A%2F%2Fapi.paypal.com%2Fv1%2Fpayments%2Fsale%2F.*%2Frefund%20openid%20https%3A%2F%2Fapi.paypal.com%2Fv1%2Fpayments%2Frefund&state=something

This is in the sandbox environment.

Any ideas on what the issue is? I was assuming this would be a simple thing to get up and running.

PayPalHere: The composite token string was not in the expected format

I'm now in a LIVE environment, but I'm receiving this error:

Data: {"correlationId":"4220c76f7f84e","errorCode":600031,"message":"Missing access token","developerMessage":"You must provide an access token when calling this API. It can be passed as either a header of the form "Authorization: Bearer " or as a query parameter called access_token.","errorType":"oauth/missing_access_token"}

@djMax

PayPal Here sample app doesn't work with live

What changes we need to make to the sample app to make it work with live environemnt. I have a merchant account with PayPal here approval but when I run the sample app and select live, receives below error:
"Relying party validation error: client_ID or redirect_URL provided in the request does not match any of the registered clients. Please check the request and try again."

What changes needs to be done to make it work?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.