Paypal OAuth login example doesn't work as exp

2020-03-27 05:11发布

问题:

I'm following this interactive login example from Paypal's site.

  public ActionResult PaypalResponse(string scope, string code)
    {
        Dictionary<string, string> configurationMap = new Dictionary<string, string>();
        configurationMap.Add("mode", "sandbox");

        APIContext apiContext = new APIContext();
        apiContext.Config = configurationMap;

        CreateFromAuthorizationCodeParameters param = new CreateFromAuthorizationCodeParameters();
        param.setClientId(clientId);
        param.setClientSecret(clientSecret);
        param.SetCode(code);

         // Exception here: 
        Tokeninfo info = Tokeninfo.CreateFromAuthorizationCode(apiContext, param);

        return null;
    }

The method CreateFromAuthorizationCode results in this (incorrect) call. Note how client ID and client secret are missing

POST https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice HTTP/1.1
Content-Type: application/x-www-form-urlencoded
User-Agent: PayPalSDK/  ;lang=DOTNET;v=4.0.30319.18051;bit=64;os=Microsoft Windows 8 Enterprise 6.2.9200.0;
Host: api.sandbox.paypal.com
Content-Length: 211
Expect: 100-continue
Connection: Keep-Alive

grant_type=authorization_code&code=d2mSEzm9xvE_l9Ibho0g6FNBVrC7wHZchJWqJfY...redacted...

The Fiddler output is

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json
Vary: Accept-Encoding
Content-Length: 76
DC: origin1-api.sandbox.paypal.com
Date: Mon, 14 Oct 2013 01:30:05 GMT
Connection: close
Set-Cookie: DC=origin1-api.sandbox.paypal.com; secure

{"error_description":"client id or secret is null","error":"invalid_client"}

回答1:

I had the exact same problem, and solved it changing call method

string postcontents = string.Format("client_id={0}&client_secret={1}&grant_type=authorization_code&redirect_uri={2}&code={3}"
                                      , System.Web.HttpUtility.UrlEncode(clientId)
                                      , System.Web.HttpUtility.UrlEncode(secret)
                                      , System.Web.HttpUtility.UrlEncode(url)
                                      , System.Web.HttpUtility.UrlEncode(code));


        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice");
        request.Credentials = new NetworkCredential(clientId, secret);
        request.Method = "POST";
        byte[] postcontentsArray = System.Text.Encoding.UTF8.GetBytes(postcontents);
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = postcontentsArray.Length;
        //OAuth.
        using (Stream requestStream = request.GetRequestStream())
        {
            requestStream.Write(postcontentsArray, 0, postcontentsArray.Length);
            requestStream.Close();
            WebResponse response = request.GetResponse();
            using (Stream responseStream = response.GetResponseStream())
            using (StreamReader reader = new StreamReader(responseStream))
            {
                string responseFromServer = reader.ReadToEnd();
                reader.Close();
                responseStream.Close();
                response.Close();
                // return SerializeToken(responseFromServer);
                dynamic dynObj = JsonConvert.DeserializeObject(responseFromServer);
                string token = dynObj["access_token"];
                //token = ser.Deserialize<ImportContacts._Default.GoogleOAuthToken>(responseFromServer);
            }
        }

Hope it helps



回答2:

I had some issues with PayPal too, albeit not with this sample. I used nodejs. This library works fine, you might want to compare notes with the one you are using and see if you find any difference. (The endpoints are certainly different). See here specifically.



回答3:

updated based on @pollirrata answer, and this is how it worked for me. Hope it will help someone.

    //code is what you get from LoginWithPayPal login page in return (query string)
public ....  GetRefreshAccessToken(string code)
    {            
        var oAuthClientId = "clientid from paypal developer site";
        var oAuthClientSecret = "client secret from paypal developer site";
        var oAuthUrl = "https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice";

        var authHeader = string.Format("Basic {0}",
                                       Convert.ToBase64String(
                                           Encoding.UTF8.GetBytes(Uri.EscapeDataString(oAuthClientId) + ":" +
                                                                  Uri.EscapeDataString((oAuthClientSecret)))
                                           ));

        //passing code here
        var postBody = string.Format("grant_type=authorization_code&code={0}", code);

        var authRequest = (HttpWebRequest)WebRequest.Create(oAuthUrl);
        authRequest.Headers.Add("Authorization", authHeader);
        authRequest.Method = "POST";
        byte[] postcontentsArray = Encoding.UTF8.GetBytes(postBody);
        authRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
        authRequest.ContentLength = postcontentsArray.Length;

        try
        {
            using (Stream stream = authRequest.GetRequestStream())
            {
                stream.Write(postcontentsArray, 0, postcontentsArray.Length);
                stream.Close();

                WebResponse response = authRequest.GetResponse();
                using (Stream responseStream = response.GetResponseStream())
                    if (responseStream != null)
                    {
                        using (var reader = new StreamReader(responseStream))
                        {
                            string responseFromServer = reader.ReadToEnd();
                            reader.Close();
                            responseStream.Close();
                            response.Close();
                            //this will return you access token which you can use to get user information
                            var responseResult =
                                JsonConvert.DeserializeObject(responseFromServer);                                
                        }
                    }
            }
        }
        catch (Exception e)
        {
            //log error
        }
    }

After this you can call GET method with new token for user information, uri: https://api.sandbox.paypal.com/v1/identity/openidconnect/userinfo/?schema=openid

Refer to: https://developer.paypal.com/webapps/developer/docs/integration/direct/identity/log-in-with-paypal/



回答4:

Im having the same issue here, and Im trying your method. However I'm getting a a 400 Bad Request after being returned to my site, at the

WebResponse response = authRequest.GetResponse();

I've verified my clientId and secret is correct, and that an authCode is being returned successfully to the method. Did you possibly also run into this issue?

Thanks

--- UPDATE ---

cleaned solution and browser cache and it does seem to work ok now



回答5:

Sailen's answer above worked for me. However, because Paypal changed their encryption to TLS in June 2016, the solution as it was written will return the following error

The request was aborted: Could not create SSL/TLS secure channel.

Based on answers provided in another thread, the SecurityProtocol needs to be set to Tls12 before creating the WebRequest. Hope this helps someone.

Here's a snippet.

var postBody = $"grant_type=authorization_code&code={code}";

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

var authRequest = (HttpWebRequest)WebRequest.Create(oAuthUrl);