Processing 3rd Party Payments via Paypal C# Rest API - c#

I have a website in which I process my user's customer's payments into their(my users) paypal account. I've created a paypal application and under the 3rd party settings I included the ability to process debit and credit card payments. Using a 3rd party account, I granted access through the third party permissions to my username. Through those steps I believe I have I've granted proper access on the paypal side.
Here is my c# code where I setup the configuration:
Dictionary<string, string> PaypalConfig = new Dictionary<string, string>();
PaypalConfig.Add("account1.apiUsername", "my api username");
PaypalConfig.Add("account1.apiPassword", "my api password");
PaypalConfig.Add("account1.apiSignature", "my api signature");
PaypalConfig.Add("subject", "email address of my user");
PaypalConfig.Add("account1.applicationId", "my app id");
PaypalConfig.Add("mode", "live");
OAuthTokenCredential tokenCredential = new OAuthTokenCredential("my client id", "my client secret", PaypalConfig);
string accessToken = tokenCredential.GetAccessToken();
//Code to fill in the transaction details
//Create Payment
Payment payment = new Payment();
payment.intent = "sale";
payment.payer = payer;
payment.transactions = transactions;
Payment createdPayment = payment.Create(accessToken);
When I run a transaction, the payment comes back approved but seems it is ignoring the subject, and money is deposited into MY ACCOUNT.
I found documentation on sending an invoice for a third party at https://developer.paypal.com/docs/classic/invoicing/ht_invoicing-3p/, but in the REST API I really do not see anything mentioned about processing 3rd party payments. It seems that I am missing something in regards to using the 3rd party account. Any help is appreciated!

Why dont you use simple redirect option to process the payments, this way, all you need to mention is your user's merchant email.
You need to pass the variables in the following format:
private void PayPal()
{
string _MerchantEmail = "youremailwithpaypal#domain.com";
string _ReturnURL = "https://www.yourwebsite.com/paymentsuccess";
string _CancelURL = "https://www.yourwebsite.com/paymentfailed";
string _CurrencyCode = "USD";
int _Amount = 100;
string _ItemName = "itme1"; //We are using this field to pass the order number
int _Discount = 10;
double _Tax = 1.5;
string _PayPalURL = $"https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business={_MerchantEmail}&return={_ReturnURL}&cancel_return={_CancelURL}&currency_code={_CurrencyCode}&amount={_Amount}&item_name={_ItemName}&discount_amount={_Discount}&tax={_Tax}";
Response.Redirect(_PayPalURL);
}
You might also need a callback URL for PayPal IPN to verify the payments status. But for your question above this should work as we are already using this code in our website.

Related

Implementing External Authentication for Mobile App in ASP.NET WebApi 2

I'm trying to build an API (using ASP.NET WebApi) that will be consumed by a native mobile app for a school project. (I'm not concerned about/developing the mobile app, this responsibility falls on a different member)
I'm at a point where I need to implement a token based Facebook login. There are a lot of tutorials available for how to implement this feature for browser based apps (this is pretty straight forward and most of it comes inbuilt), but I don't think I follow how this would work with native apps. What I don't understand is how the redirects would work?
According to this link, nothing needs to be handled specifically by my server. And I don't think I understand how this would work? How would the tokens from Facebook be handled?
Also, what part of token handling should I implement, I couldn't really find good documentation for WebApi external login authentication.
Anyway, if someone could point me to the exact flow of token exchanges that happen and what is implemented by default by ASP.NET, that would be super helpful.
Also, the biggest point of confusion for me is I don't understand how the token returned by Facebook will be handled.
I assume the token will be returned to the client (mobile app), how do I get access to it on my server?
How do I create a local token from facebook's token?
Is this all done internally/auto-magically by ASP.NET?
I'm sorry if this is something I should've been able to figure out. I did do quite a bit of research and I found myself drowning in (related & unrelated) information. I don't think I even know how to search for the information I need.
Some links I've read:
Claims And Token Based Authentication (ASP.NET Web API)
Token Based Authentication using ASP.NET Web API 2, Owin, and Identity
ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app
I had to do pretty much the same thing for an application I was working on. I also had a lot of trouble finding information about it. It seemed like everything I found was close to what I needed, but not exactly the solution. I ended up taking bits and pieces from a bunch of different blog posts, articles, etc. and putting them all together to get it to work.
I remember two of the links you posted "Claims and Token Based Authentication" and "ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app" as being ones that had useful information.
I can't give you a comprehensive answer since I don't remember everything I had to do, nor did I even understand everything I was doing at the time, but I can give you the general idea. You are on the right track.
Essentially I ended up using the token granted by Facebook to confirm that they were logged into their Facebook account, created a user based on their Facebook user ID, and granted them my own bearer token that they could use to access my API.
The flow looks something like this:
Client authenticates with Facebook via whatever method (we used oauth.io)
Facebook returns them a token
Client sends token information to the registration endpoint of my WebApi controller
The token is validated using Facebook's Graph API, which returns user info
A user is created in the database via ASP.NET Identity with their Facebook user ID as the key
Client sends token information to the authentication endpoint of my WebApi controller
The token is validated using Facebook's Graph API, which returns user info
The user info is used to look up the user in the database, confirm they have previously registered
ASP.NET Identity is used to generate a new token for that user
That token is returned to the client
Client includes an Authorization header in all future HTTP requests with the new token granted by my service (ex. "Authorization: Bearer TOKEN")
If the WebApi endpoint has the [Authorize] attribute, ASP.NET Identity will automatically validate the bearer token and refuse access if it is not valid
There ended up being a lot of custom code for implementing the OAuth stuff with ASP.NET Identity, and those links you included show you some of that. Hopefully this information will help you a little bit, sorry I couldn't help more.
I followed this article. The flow is basically this
The server has the facebook keys just like with web login
The app asks for available social logins and displays buttons (you can hardcode this I guess)
When a button is pressed the app opens a browser and sets the URL to the one related to the specified social login. The ASP.NET then redirects the browser to facebook/google/whatever with the appropriate Challenge
The user might be logged in or not and might have given permission to your app or not. After he gives the permissions facebook redirects back to the provided callback URL
At that point you can get the external login info from the SignInManager and check if the user already exists and if you should create a new account
Finally a token is generated and the browser is redirected to a URL in which the token is placed. The app gets the token from the URL and closes the browser. Uses the token to proceed with API requests.
Honestly I have no idea if this approach is legit...
The code of the action buttons should redirect to:
public async Task<IEnumerable<ExternalLoginDto>> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationScheme> loginProviders = await SignInManager.GetExternalAuthenticationSchemesAsync();
var logins = new List<ExternalLoginDto>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationScheme authenticationScheme in loginProviders)
{
var routeValues = new
{
provider = authenticationScheme.Name,
response_type = "token",
client_id = Configuration["Jwt:Issuer"],
redirect_uri = $"{Request.Scheme}//{Request.Host}{returnUrl}",
state = state
};
var login = new ExternalLoginDto
{
Name = authenticationScheme.DisplayName,
Url = Url.RouteUrl("ExternalLogin", routeValues),
State = state
};
logins.Add(login);
}
return logins;
}
The code for the callback action:
[Authorize(AuthenticationSchemes = "Identity.External")]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IActionResult> GetExternalLogin(string provider, string state = null, string client_id = null, string error = null)
{
if (error != null)
{
ThrowBadRequest(error);
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider);
}
string providerKey = User.FindFirstValue(ClaimTypes.NameIdentifier);
var externalLoginInfo = new ExternalLoginInfo(User, User.Identity.AuthenticationType, providerKey, User.Identity.AuthenticationType);
if (externalLoginInfo.LoginProvider != provider)
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
return new ChallengeResult(provider);
}
var userLoginInfo = new UserLoginInfo(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, externalLoginInfo.ProviderDisplayName);
User user = await UserManager.FindByLoginAsync(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey);
if (client_id != Configuration["Jwt:Issuer"])
{
return Redirect($"/#error=invalid_client_id_{client_id}");
}
if (user != null)
{
return await LoginWithLocalUser(user, state);
}
else
{
string email = null;
string firstName = null;
string lastName = null;
IEnumerable<Claim> claims = externalLoginInfo.Principal.Claims;
if (externalLoginInfo.LoginProvider == "Google")
{
email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
firstName = claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
lastName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
}
else if (externalLoginInfo.LoginProvider == "Facebook")
{
email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
string[] nameParts = claims.First(c => c.Type == ClaimTypes.Name)?.Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
firstName = nameParts?.First();
lastName = nameParts?.Last();
}
//some fallback just in case
firstName ??= externalLoginInfo.Principal.Identity.Name;
lastName ??= externalLoginInfo.Principal.Identity.Name;
user = new User
{
UserName = email,
Email = email,
FirstName = firstName,
LastName = lastName,
EmailConfirmed = true //if the user logs in with Facebook consider the e-mail confirmed
};
IdentityResult userCreationResult = await UserManager.CreateAsync(user);
if (userCreationResult.Succeeded)
{
userCreationResult = await UserManager.AddLoginAsync(user, userLoginInfo);
if (userCreationResult.Succeeded)
{
return await LoginWithLocalUser(user, state);
}
}
string identityErrrors = String.Join(" ", userCreationResult.Errors.Select(ie => ie.Description));
Logger.LogWarning($"Error registering user with external login. Email:{email}, Errors:" + Environment.NewLine + identityErrrors);
return Redirect($"/#error={identityErrrors}");
}
}
private async Task<RedirectResult> LoginWithLocalUser(User user, string state)
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
DateTime expirationDate = DateTime.UtcNow.AddDays(365);
string token = user.GenerateJwtToken(Configuration["Jwt:Key"], Configuration["Jwt:Issuer"], expirationDate);
return Redirect($"/#access_token={token}&token_type=bearer&expires_in={(int)(expirationDate - DateTime.UtcNow).TotalSeconds}&state={state}");
}

PayPal Express - How to integrate Card payments?

Question background:
I've been developing with the PayPal C# API and have implemented an 'Express Checkout' solution. This works perfectly but I can only pay with a PayPal account. I of course want the ability to also pay with Cards.
Code:
Parameters set as part of my request to the API:
encoder["METHOD"] = "SetExpressCheckout";
encoder["RETURNURL"] = returnURL;
encoder["CANCELURL"] = cancelURL;
encoder["BRANDNAME"] = "Test App";
encoder["PAYMENTREQUEST_0_AMT"] = "120.00";
encoder["PAYMENTREQUEST_0_ITEMAMT"] = "120.00";
encoder["PAYMENTREQUEST_0_PAYMENTACTION"] = "Sale";
encoder["PAYMENTREQUEST_0_CURRENCYCODE"] = "USD";
encoder["L_PAYMENTREQUEST_0_NAME1"] = "test1";
encoder["L_PAYMENTREQUEST_0_AMT1"] = "20.00";
encoder["L_PAYMENTREQUEST_0_QTY1"] = "1";
encoder["L_PAYMENTREQUEST_0_NAME2"] = "test2";
encoder["L_PAYMENTREQUEST_0_AMT2"] = "20.00";
encoder["L_PAYMENTREQUEST_0_QTY2"] = "2";
encoder["L_PAYMENTREQUEST_0_NAME3"] = "test3";
encoder["L_PAYMENTREQUEST_0_AMT3"] = "20.00";
encoder["L_PAYMENTREQUEST_0_QTY3"] = "3";
Current Implementation:
Users are taken to PayPal to pay through their account then returned to my site:
What I require:
I need the user to be able to pay both through their account or with a card if they do not have a PayPal account, then be returned to my site. Is this possible through the Express checkout? If so then how do I implement it?:
You need to make sure "PayPal Account Optional" is enabled in your PayPal account profile under Website Payment Preferences.
Then in your SetExpressCheckoutRequest you need to include the following parameters:
SOLUTIONTYPE=Sole
LANDINGPAGE=Billing
USERSELECTEDFUNDINGSOURCE=CreditCard
Then you also need to make sure you have the API version updated to at least 109.0. That should give you what you're after.

Error in transaction processing when using SetPaymentsOptionsRequest

I'm working on integrating PayPal into a client's ecommerce site. Using the sandbox, we got everything working fine. I now need to add in SetPaymentOptionsRequest to prevent the user from changing his shipping address (they enter it on our site, so they can't change it at PayPal due to different shipping costs calculated on our site). It appears to work fine, but I get a 3005 error when logging into the PayPal sandbox site to confirm the transaction. Below is the relevant code (C#):
public string MakeChainedPayment(params params) {
var request = new PayRequest {
requestEnvelope = new RequestEnvelope("en_us"),
actionType = "CREATE",
cancelUrl = this._cancelUrl,
currencyCode = this._currencyCode,
returnUrl = this._returnUrl,
ipnNotificationUrl = this._ipnNotificationUrl
};
// Some code to generate receivers, not important for this problem, I don't think
var response = this._paymentService.Pay(request);
switch (response.paymentExecStatus) {
// This always returns "CREATED", as I'd want, so good up to here.
case "CREATED":
// If I leave this code out, PayPal works fine, but I need
// this part to do the shipping address verification.
var p = new SetPaymentOptionsRequest();
p.senderOptions = new SenderOptions();
p.senderOptions.addressOverride = false;
p.senderOptions.shippingAddress = new ShippingAddressInfo {
// Setting from params: city, country, zip, state, street1, street2
};
p.payKey = response.payKey;
p.requestEnvelope = request.requestEnvelope;
SetPaymentOptionsResponse r = _paymentService.SetPaymentOptions(payOptsReq);
break;
// This always retuns r.error.Count = 0, r.responseEnvelope.ack = "SUCCESS",
// so I think I'm good to go.
}
if (this._useSandbox) {
return string.Concat("https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=", response.payKey);
}
return string.Concat("https://www.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=", response.payKey);
}
Paypal returns this message when your Paypal account's email address has not been verified. To verify your Paypal Email account, please follow the following steps:
Log into your Paypal Account. You should be in the “Overview” tab.
Click on your Email address, under “Business account overview”, you will be taken to a Web page listing your Paypal Email addresses.
Select your Primary Adress.
Click on the “Confirm” button.
Follow the rest of the Paypal instructions.
The problem was what I was passing in for the country; I was sending in "USA", and it should be "US".

Google Analytics throws 403 error

I am attempting to download metric data from Google Analytics using C# and am performing user authentication with OAuth 2.0. I'm using the Installed Application authorisation flow, which requires logging into Google and copy-and-pasting a code into the application. I'm following the code taken from google-api-dotnet-client:
private void DownloadData()
{
Service = new AnalyticsService(new BaseClientService.Initializer() {
Authenticator = CreateAuthenticator(),
});
var request = service.Data.Ga.Get(AccountID, StartDate, EndDate, Metrics);
request.Dimensions = Dimensions;
request.StartIndex = 1;
request.MaxResults = 10000;
var response = request.Execute(); // throws Google.GoogleApiException
}
private IAuthenticator CreateAuthenticator()
{
var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description) {
ClientIdentifier = "123456789012.apps.googleusercontent.com",
ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxx",
};
return new OAuth2Authenticator<NativeApplicationClient>(provider, Login);
}
private static IAuthorizationState Login(NativeApplicationClient arg)
{
// Generate the authorization URL.
IAuthorizationState state = new AuthorizationState(new[] { AnalyticsService.Scopes.AnalyticsReadonly.GetStringValue() });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
Uri authUri = arg.RequestUserAuthorization(state);
// Request authorization from the user by opening a browser window.
Process.Start(authUri.ToString());
Console.Write("Google Authorization Code: ");
string authCode = Console.ReadLine();
// Retrieve the access token by using the authorization code.
state = arg.ProcessUserAuthorization(authCode, state);
return state;
}
The Google account xxxxxx#gmail.com registered the Client ID and secret. The same account has full administration rights in Google Analytics. When I try to pull data from Google Analytics, it goes through the authorisation process, which appears to work properly. Then it fails with:
Google.GoogleApiException
Google.Apis.Requests.RequestError
User does not have sufficient permissions for this profile. [403]
Errors [
Message[User does not have sufficient permissions for this profile.] Location[ - ] Reason [insufficientPermissions] Domain[global]
]
I've been struggling with this for a few hours. I've double checked that the correct user is being used, and is authorised on Google Analytics. I'm at a loss as to what is misconfigured. Any ideas as to what requires configuring or changing?
If auth seems to be working working then my suggestion is that you make sure you're providing the correct ID because based on your code snippet:
var request = service.Data.Ga.Get(AccountID, StartDate, EndDate, Metrics);
one can only assume that you're using the Account ID. If so, that is incorrect and you'd receive the error you've encountered. You need to query with the Profile ID.
If you login to Google Analytics using the web interface you'll see the following pattern in URL of the browser's address bar:
/a12345w654321p9876543/
The number following the p is the profile ID, so 9876543 in the example above. Make sure you're using that and actually you should be using the table id which would be ga:9876543.
If it isn't an ID issue then instead query the Management API to list accounts and see what you have access to and to verify auth is working correctly.
This can help : https://developers.google.com/analytics/devguides/reporting/core/v3/coreErrors, look error 403.
//Thanks for this post. The required profile id can be read from the account summaries.
Dictionary profiles = new Dictionary();
var accounts = service.Management.AccountSummaries.List().Execute();
foreach (var account in accounts.Items)
{
var profileId = account.WebProperties[0].Profiles[0].Id;
profiles.Add("ga:" + profileId, account.Name);
}

Facebook C# SDk user registration

I am trying to implement user registration on my mvc3 site using fb. My question is regard this bit of code
FacebookClient fbClient = new FacebookClient(accessToken);
dynamic me = fbClient.Get("me?fields=id,name");
What other parameters can be specified in the request "me?fields=id,name,??". My application requires Email Address, phone number, address and name (first name, last name). I would be grateful if someone could tell me or better yet point to to somewhere I can find documentation on this.
This is a sample of the parameters you get inside dynamic me = fb.Get("me") without user permission:
"id":"894555532"
"name":"John Doe"
"first_name":"John"
"last_name":"Doe"
"link":"http://www.facebook.com/johndoe"
"username":"john"
"bio":"Sample bio"
"quotes":"\"Sample quote""
"work":[{"employer":{"id":"39233323343","name":"Sample Company"}
"position":{"id":"142461033332450","name":"Backend Developer"}
"projects":[{"id":"214103971985333"
"name":"Coors Light, Sample Project"}]}]
"favorite_teams":[{"id":"171522852874952","name":"Juventus"},{"id":"112325268793829","name":"Barcelona F.C."}]
"favorite_athletes":[{"id":"326971266226","name":"Alessandro Del Piero"}]
"gender":"male"
"timezone":-6
"locale":"en_US"
"verified":true
"updated_time""2012-01-24T09:12:17+0000"}
"email" requires user permission
I'm sure there are other things you can get, though there is no official list for c# sdk yet.
This is a sample of how to get all that info:
var fb = new FacebookWebClient();
dynamic me = fb.Get("me");
imgProfilePic.ImageUrl = string.Format("https://graph.facebook.com/{0}/picture", me.id);
lblName.Text = me.name;
lblFirstName.Text = me.first_name;
lblLastName.Text = me.last_name;
Here's an updated / complete list a scopes for Facebook C# SDK:
ads_management
create_event
create_note
email
export_stream
friends_about_me
friends_activities
friends_birthday
friends_checkins
friends_education_history
friends_events
friends_games_activity
friends_groups
friends_hometown
friends_interests
friends_likes
friends_location
friends_location_posts
friends_notes
friends_online_presence
friends_photo_video_tags
friends_photos
friends_questions
friends_relationship_details
friends_relationships
friends_religion_politics
friends_status
friends_subscriptions
friends_videos
friends_website
friends_work_history
manage_friendlists
manage_notifications
manage_pages
offline_access
photo_upload
publish_actions
publish_checkins
publish_stream
read_friendlists
read_insights
read_mailbox
read_requests
read_stream
rsvp_event
share_item
sms
status_update
user_about_me
user_activities
user_birthday
user_checkins
user_education_history
user_events
user_games_activity
user_groups
user_hometown
user_interests
user_likes
user_location
user_location_posts
user_notes
user_online_presence
user_photo_video_tags
user_photos
user_questions
user_relationship_details
user_relationships
user_religion_politics
user_status
user_subscriptions
user_videos
user_website
user_work_history
video_upload xmpp_login

Categories

Resources