Implementation of Paypal in single page application - angularjs

I am currently working on a game, which will consist out of an API-based backend, along with a web frontend (which is a single page app, in AngularJS) and on several mobile devices (using Cordova). I am planning on serving the SPA over the main domain name, along with a CDN. The SPA (and homepage) will all be static HTML/Javascript/CSS files, so the only part which is dynamic is the api. The domain name for the "main server" hosting the static sites will be in the style of example.com, the one for the api will be api.example.com
I am wondering how I can integrate Paypal into this scenario though. The internet doesn't seem to offer much advice on how to integrate it into S.P.A's like this...or my google-fu could be off. Thanks for the replies.

Below is how I am handling the situation,
I have a button to say pay with paypal and onClick I open a new window -> window.open("/paypalCreate", width = "20px", height = "20px");
and I capture this get request "/paypalCreate" in my node.js server and call create method which looks liek below
exports.create = function (req, res) {
//Payment object
var payment = {
//fill details from DB
};
//Passing the payment over to PayPal
paypal.payment.create(payment, function (error, payment) {
if (error) {
console.log(error);
} else {
if (payment.payer.payment_method === 'paypal') {
req.session.paymentId = payment.id;
var redirectUrl;
for (var i = 0; i < payment.links.length; i++) {
var link = payment.links[i];
if (link.method === 'REDIRECT') {
redirectUrl = link.href;
}
}
res.redirect(redirectUrl);
}
}
});
};
This redirects user to paypal and once user confirms or cancels payment, the redirect urls are called. And in the success redirect url I capture the payment details into the databse and render a html in this opened window with the confirmation.
exports.execute = function (req, res) {
var paymentId = req.session.paymentId;
var payerId = req.param('PayerID');
// 1. if this is executed, then that means the payment was successful, now store the paymentId, payerId and token into the database
// 2. At the close of the popup window open a confirmation for the reserved listing
var details = {"payer_id": payerId};
paypal.payment.execute(paymentId, details, function (error, payment) {
if (error) {
console.log(error);
} else {
//res.send("Hell yeah!");
res.render('paypalSuccess', {payerId: payerId, paymentId: paymentId});
}
});
};
Once the user closes the opened window in which paypal was being handled the orginal SPA window will be refreshed and thus getting the payment details from the DB and here you can handle the SPA in whatever way you want.
I know that this is a dirty hack, but like you I couldnt find a better way. Please let me know if this works for you or if you have a found a better way to do tihs.
cheers,
Chidan

Related

Linking Twitter account to user account (twitter-passport)

Currently, a user is able to login in and sign up for my application no problem. I've then added a "Link your twitter user to account" button which when clicked takes the user to '/auth/twitter'. This then kicks off passport-twitter and the oAuth process begins.
Right now, I'm using passport-twitter as the package for twitter oAuth. This process works. I'm able to get the user successfully authenticated. Here is the code.
However two problems: I don't see a way to 1) keep the user signed into Twitter so they don't have to keep doing this flow of reconnecting their twitter every time they want to push content to it from my app. and 2) associate the Twitter user and the signed in user to my application. Long term, I plan to add other social media accounts, so the user will have multiple social media linked. Twitter will be just one.
Problem #2: I wasn't able to do an axios.get call from my redux store or from the front end to '/auth/twitter/' otherwise I could then just get the information back from the call and then post it to the user's table (right?). So, instead I'm accessing '/auth/twitter' from an tag in the front end to kick off the flow.
passport.use(
new TwitterStrategy(
{
consumerKey: "XXX",
consumerSecret: "XXX",
callbackURL: "http://localhost:8080/auth/twitter/callback",
// callbackURL: "http://www.localhost:8080/home",
includeEmail: true,
},
async(accessToken, refreshToken, profile, cb) => {
console.log('got the prodile')
const twitterIDforOAuth = profile.id
const { id, username } = profile;
let theuser = await User.findOne({
where: {
twitterID: id
}
})
if(theuser){
console.log('FOUND USER', '\n', theuser)
} else {
try {
console.log('NO USER FOUND')
var passwordUser = (Math.random() + 1).toString(36).substring(7);
console.log('CREATING USER')
theuser = await Promise.all([
User.create({
twitterID: id,
username : username,
password: passwordUser
})
])
console.log('USER CREATED');
} catch (error) {
console.log(error);
}
}
//this callback calls the auth/callback url to kick off the redirect process
// need to send username and password to /auth/signup
return cb(null, {username: username, password: passwordUser})
//Line below sends too much data that is irrelevant for the user... lets review it?
// return cb(null, {username: twitterIDforOAuth})
}
)
);
app.get('/auth/twitter', passport.authenticate("twitter"));
app.get(
"/auth/twitter/callback",
passport.authenticate("twitter", {
failureRedirect: "/login",
failureMessage: true,
session: false
}),
async (req, res) => {
var user = req.user;
console.log(user.username, user.password);
//GET USERNAME AND PASSWORD
var username = user.username;
var password = user.password;
///they need to login the app
//auth/login
res.redirect('/AccountSettings')
}
);
The user is being redirected to /AccountSettings while they go through this flow, so I know that the user is 100% authenticated and signed in with Twitter (otherwise they'd be pushed to /login, which isn't happen).
Most people in this flow create a user in their database using the information returned from Twitter.
However, I'm trying to link this information to the signed in user, and keep them signed into Twitter so the user doesn't need to keep reconnecting their Twitter account (at least not often). (With access to their Twitter account, my plan is to allow them to push content to it)
Currently I'm hitting the '/auth/twitter' route with an tag which's href takes it to '/auth/twitter'. Is this the right way about it or is this approach causing my linkage issue?
What are people's recommendation for this issue? Whats the right way to approach linking social media accounts to a signed in user's account?
I'm using Express, Redux, React, Postgres, and passport-twitter
SOLUTION: How to passing data in TwitterStrategy, PassportJS?
had to create a state object outside the /auth/twitter route and then added a id param to the /auth/twitter route so the full route was /auth/twitter/:id
once I got the id I saved it to a state route outside the route in the server file that was accessible to the callback function later in the proces.

React native, get value from url browser

How do i get the value of url from the browser? using the react native
If you can make callbacks from the gateway website, then I recommend to use deep linking to handle flow between app and browser. Basically, your app will open the gateway website for payment, and depending on payment result, the website will make a callback to the app using its deep link. App then will listen to the link, take out necessary information and continue to proceed.
What you need to do is:
Set up deep linking in your app. You should follow the guide from official website (here) to enable it. Let pick a random URL here for linking, e.g. gatewaylistener
Set the necessary callbacks from gateway to your app. In your case, since you need to handle successful payment and failed payment, you can add 2 callbacks, e.g. gatewaylistener://success?id={paymentId} and gatewaylistener://error?id={paymentId}
Finally, you need to listen to web browser from the app. One way to do that is add listener right inside the component opening the gateway.
// setup
componentDidMount() {
Linking.getInitialURL().then((url) => {
if (url) {
this.handleOpenURL(url)
}
}).catch(err => {})
Linking.addEventListener('url', this.handleOpenURL)
}
componentWillUnmount() {
Linking.removeEventListener('url', this.handleOpenURL)
}
// open your gateway
async openGateWay = () => {
const { addNewOrderGatewayToken } = this.props
const url = `${BASEURL}${addNewOrderGatewayToken}`
const canOpen = await Linking.canOpenURL(url)
if (canOpen) {
this.props.dispatch(setPaymentStatus('checked'))
Linking.openURL(url)
}
}
// handle gateway callbacks
handleOpenURL = (url) => {
if (isSucceedPayment(url)) { // your condition
// handle success payment
} else {
// handle failure
}
}

How can I prompt user for more information during sign-in/registration process with Firebase?

I am using the firebaseUI toolset to allow users to login to my app.
I'm also using the firebase.auth().onAuthStateChanged method to redirect them to the main application once they are logged in.
What I would like to do is, during the sign-in process...if they are a new user, prompt them for a displayname to use (to override whatever name is given by the 3rd party provider).
Right now, once they login, they are redirected to the app..and it's not obvious how I can have a smooth workflow that would provide a modal /screen to allow them to create a display name before continuing onto the app.
Is there a recommended best practice of how to capture/prompt for additional information during the first sign-in process, which I would then store in my firebase /users collection?
Right now it will just auto redirect to the main app.
componentDidMount() {
//console.log(this.props.isLoading)
firebase.auth().onAuthStateChanged(user => {
if(user) {
this.props.setUser(user);
this.props.history.push('/');
}
callbacks : {
signInSuccessWithAuthResult: function(authResult, redirectUrl) {
var user = authResult.user;
var credential = authResult.credential;
var isNewUser = authResult.additionalUserInfo.isNewUser;
var providerId = authResult.additionalUserInfo.providerId;
var operationType = authResult.operationType;
if(isNewUser)
{
//prompt user to enter a displayName to use with the application
}
// Do something with the returned AuthResult.
// Return type determines whether we continue the redirect automatically
// or whether we leave that to developer to handle.
return true;
},
},

Plaid: how to create public token in the front end (Ionic/angular) and send to server

I am follow this tutorial in order to get a transactions/accounts detail from the plaid API. Plaid'd quickstart guide user ejs in order to send to the server with the onSuccess function. How do I create this token using ionic?
Plaid quick guide also suggests that we use code blow
var linkHandler = Plaid.create({
env: 'sandbox',
clientName: 'Client Name',
key: '<PUBLIC_KEY>',
product: ['auth', 'transactions'],
token: '<GENERATED_PUBLIC_TOKEN>',
onSuccess: function(public_token, metadata) {
// You do not need to repeat the /item/public_token/exchange
// process when a user uses Link in update mode.
// The Item's access_token has not changed.
},
and also suggest to use this code
// Create a public_token for use with Plaid Link's update mode
client.createPublicToken(ACCESS_TOKEN, (err, result) => {
// Handle err
// Use the generated public_token to initialize Plaid Link in update
// mode for a user's Item so that they can provide updated credentials
// or MFA information
const publicToken = result.public_token;
});
in order to create a public token and get the access token. I can't use this function because I'm getting an error 'Plaid and/or client is not defined
How do I create this public token using Ionic front end and node back end?
What's the workflow here?
Thanks in advance
On the server side, you'll need to initialize the Plaid node client library first. You will also want to make an exchange token call, to exchange the public_token from Link for an API access_token. You'll then save the access_token and use it to retrieve transaction and account data:
// Initialize the Plaid API client with your API keys (https://dashboard.plaid.com/account/keys)
// Use plaid.environments.production, plaid.environments.development, or plaid.environments.sandbox
const plaid = require('plaid');
const client = new plaid.Client(client_id, secret, public_key, plaid.environments.sandbox);
client.exchangePublicToken(PUBLIC_TOKEN, function(error, tokenResponse) {
if (error != null) {
var msg = 'Could not exchange public_token!';
console.log(msg + '\n' + error);
}
const ACCESS_TOKEN = tokenResponse.access_token;
const ITEM_ID = tokenResponse.item_id;
console.log('Access Token: ' + ACCESS_TOKEN);
console.log('Item ID: ' + ITEM_ID);
// Now retrieve transactions or account information with the access_token
});
For the client-side in your Ionic app, you'll need to include the link-initialize.js script before calling Plaid.create. Specifically:
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js">
</script>
Here's a full client-side HTML example:
<button id="link-button">Link Account</button>
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script type="text/javascript">
var handler = Plaid.create({
clientName: 'Plaid Walkthrough Demo',
env: 'sandbox',
key: '[PUBLIC_KEY]', // public_key is at https://dashboard.plaid.com/account/keys
product: ['auth'],
onLoad: function() {
// Optional, called when Link loads
},
onSuccess: function(public_token, metadata) {
// Send the public_token to your app server.
// The metadata object contains info about the institution the
// user selected and the account ID, if `selectAccount` is enabled.
$.post('/get_access_token', {
public_token: public_token,
});
},
onExit: function(err, metadata) {
// The user exited the Link flow.
}
});
</script>
An Angular library was recently created: click here and here
I had some issues implementing Plaid successfully at first; these tips should help:
Implement the library as shown in the second link above. Make sure for step two you import in your app.module.ts file. Don't use the jQuery provided in the documentation.
Using this library, a button will be automatically created within the Angular element <mr-ngx-plaid-link-button>. This button will act as a submit button unless you use DOM or other methods to change it to type button on ngAfterViewInit()
All five events in step three are listeners for various events. The onSuccess() callback will return the public token - only after you have (a) successfully submitted bank credentials (user_good / pass_good on Sandbox) and (b) clicked the Continue button to exit the Plaid Link

SignalR doesn't push message to client

I am implementing functionality to notify the user of long running job completions using SignalR in an AngularJS application.I have created groups of user based on their name,so for each user a group of his name and different connectionids which he has opened up will be created and he would be notified by his group. I want to notify the user on two pages i.e. landing Page and Job Run Page as even if the user is on landing page and job run completes he should be notified of it.
For the same reason i am creating group by his name on both the pages,so that if he is on any page he would be nofied through the group.
On landing page controller js file i have written code to add the user in group as follow...
$rootScope.signalRHub = $.connection.signalRHub;
$rootScope.hubStart = null;
$rootScope.startHub = function () {
if ($rootScope.hubStart == null)
{
$rootScope.hubStart = $.connection.hub.start();
}
return $rootScope.hubStart;
}
$scope.$on('$locationChangeStart', function (event) {
if ($rootScope.userName != "") {
$rootScope.signalRHub.server.leaveGroup($rootScope.userName);
}
});
// Start the connection
$rootScope.startHub().done(function () {
$rootScope.signalRHub.server.joinGroup($rootScope.userName);
});
on Job Run controller js file i have written following code....
$rootScope.signalRHub.client.showNotification = function (message) {
notify('Your notification message');//notify is the angular js directive injected in this controller which runs fine
};
$scope.$on('$locationChangeStart', function (event) {
$rootScope.signalRHub.server.leaveGroup($rootScope.studyid);
});
// Start the connection
$rootScope.startHub().done(function () {
$rootScope.signalRHub.server.joinGroup($rootScope.userName
});
My Hub File.....
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class SignalRHub : Hub
{
public Task JoinGroup(string groupName)
{
return Groups.Add(Context.ConnectionId, groupName);
}
public Task LeaveGroup(string groupName)
{
return Groups.Remove(Context.ConnectionId, groupName);
}
public void ShowNotification(string jobRunDetailId, string userName)
{
if (!string.IsNullOrEmpty(userName))
{
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRHub>();
context.Clients.Group(userName).showNotification(jobRunDetailId);
}
}
}
The issue is when i run the application the group add functionality for both pages works fine.but when i call "showNotification" from Hub it doesn't show any message.
But strange thing is if i comment the "$rootScope.startHub().done...." function on landing page then the jobrun page notify functionality works fine.I am not sure if writing "$rootScope.startHub().done()..." on two places is creating this problem.please help.
You need to wire up all callbacks before calling start. If you turn client side logging on, it'll tell you what hubs you are subscribed to.
Aside:
[EnableCors] is a webapi specific attribute that does not work in SignalR.

Resources