Tracking payment status in react native webview - react-native

I have a React Native app where i'm using sandbox rest api to complete paypal payment with the help of react-native-webview. This is successfully redirecting me to paypal checkout page and doing the payment. But i need to take user to the previous screen of app after successfull payment. I need to know if the transaction is successfull or not. Can i do that with websocket? If so, how can i do that?

onNavigationStateChange={(navState) => {
console.log("navState.url ", navState)
if (navState.url === "your success url") {
// navigation.navigate('Home');
} else if (navState.url === 'your cancel url') {
// navigation.goBack();
}
}}

You can use a deeplink to get back to the app. But as far as being notified, if the transaction is completing without a capture API call from you, then a webhook to your public web server (yes it must be a server, not native app) will work best for a guaranteed notification, since the return is not guaranteed.

Related

Passing Login Details to React Native WebView

I'm trying to pass login details to a WebView, basically, my use case is, I have a login page built with React Native, after a successful login I wanted to redirect the user to a WebView login with the login details so the WebView doesn't render the login page in itself. So, to achieve this I attach the ref to webView like so
<WebView ref={webViewRef} ... />
With the login page built with ReactNative, the user will enter their credentials, once the login is successful I'll get the user details from the backend as a response to the LOGIN Post API Call, so I passed the response to the postMessage function
const response = await LOGIN({...credentials});
webviewRef.current.postMessage(response.data);
And to the React Web app, I used the below code to add the listener
window.addEventListener("message", (message) => {
alert(JSON.stringify(message.data));
});
But, I'm not getting the data with message.data.
Any workaround would highly be appreciated
You have to use injectJavaScript method on the webviewRef to send data from the app to the web(i.e., to react side). The post message will be used vice-versa i.e., to send data from react side to the app side. The solution below would solve your issue.
First on react side, set the custom function on the window object.
window.onUserLogin = function(userDetails) {
alert(`userDetails are ${JSON.stringify(userDetails)}`)
}
Now on the react-native side, you have the webViewRef. Using that please make the below call.
const USER_DETAILS = {
userName: "Haider"
};
webViewRef.current.injectJavaScript(`window.onUserLogin(${JSON.stringfy(USER_DETAILS)});true;`)

Stripe Connect Account - return_url - Link back to Expo application

I'm on-boarding users onto Stripe connect. My node server generates a temporary HTTPS URL so that customers can sign on. According to their docs I need to provide a URL for when they complete the application.
https://stripe.com/docs/api/account_links/create#create_account_link
I have an Expo application. The user will open up the URL in their browser. However when they complete their application I would like them to go back to Expo App. If I try to use expo://MYAPP/ as the return_url, Stripe does not recognize the URL schema.
Does anyone have an idea how i can return the user back into my application after completing their on-boarding done via the browser?
For anyone one out there who runs into this post, this is was my solution. Your app has to link to a website. I am using Expo, but this is the React code to generate the link.
import * as WebBrowser from 'expo-web-browser';
import * as Linking from 'expo-linking';
const openPage = async () => {
try {
const result = await WebBrowser.openAuthSessionAsync(
`${url}?linkingUri=${Linking.createURL('/?')}`,
);
let redirectData;
if (result.url) {
redirectData = Linking.parse(result.url);
}
setstate({ result, redirectData });
} catch (error) {
console.log(error);
}
};
When you load the site, make sure to pass the URL that was generated from your backend
Backend code:
stripe.accountLinks
.create({
type: 'account_onboarding',
account: accountID,
refresh_url: `https://website.com/refresh`,
return_url: `https://website.com/return`,
})
When the user has the site open, have a button that redirects to the stripe URL.This is how i thought it went first
App -> Stripe connect
instead you have to approach it like this
App -> Website -> Stripe connect

user authentication in a react native app

I'm building a react native app in which users can login. After a user logs in, the server returns a auth token (jwt) which is stored on the device. This all works.
Now, the problem is with authenticating the user whenever something 'happens'.
After the user logs in and the token is stored, he is send to the screen 'Main'. On that screen (and all the other 'secured' screens), I want to check the auth token. I currently have the following function to do this (simplified):
// get the auth token out of the redux store
const authToken = useSelector(state => state.auth.authToken)
// the function to authenticate a user
const authenticateUser = () => {
try {
fetch('http://URL_TO_SERVER/auth/authenticate-user', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + authToken
}
})
.then(response => response.json())
.then(responseJSON => {
if (responseJSON.response === 'OK') {
// user is authenticated
} else {
// user is NOT authenticated
}
})
}
// only run the function once
useEffect(() => {
authenticateUser()
}, [])
This works, but there is a 'lag' (because fetch returns a promise). When I open the app and go to I screen whilst I'm not logged in, the screen is shown for just a second, and after that, I'm redirected to the login screen. So it works, but I'm not sure that this is the correct way to do so.
I could add a 'layer' to each screen and show a loading modal untill the authenticateUser-function has ran, but I don't think that's the correct way to do so.
My question is: what is the best way to secure screens in a react native app? Is the way I'm doing it OK, or should I switch to another method?
Thanks in advance!
EDIT: I have checked the following articles before asking this question.
Authentication with React Native and API backend
https://scotch.io/tutorials/react-native-app-with-authentication-and-user-management-in-15-minutes
You need to come up with better logic for your auth checks. Usually there is no need to check token every time you open a new screen. Even in your example, you log in and then get sent to a Main screen only to check auth token you've just received. Likewise, should user even see "go to main screen" button when user is clearly not logged in? Do you really want to check for token every time new screen opens in the app? What happens if token is valid by the time you open the screen, but, as the time passes and user stays on the same screen, token becomes invalid?
Try this:
create a part of redux store (e.g. reducer) that will handle current authentication state. Simple "isAuthenticated" flag will do for start
you can access this flag from any screen that is connected to redux
when receiving JWT you can read it's expiration date. So, if you refreshed the token 5 minutes ago and it's not going to expire for the next 2 hours, there is no need to check if token is valid, because you can just assume that by comparing expiration date with current date any time you want
use "isAuthenticated" flag to determine whether or not to show the "go to Main screen" button, so that logged out users will not even see that button
if you need even more control, hook into navigation to check where user is trying to navigate to and allow/deny that by checking against "isAuthenticated" flag in redux store. Take a look here and here
create a service to keep track on token expiration dates and refresh tokens ahead of time if needed, or periodically check if current token is valid, and set "isAuthenticated" to false if it isn't. Create wrappers around your network functions (fetch in your example) and notify this service if status 401 is received in response to any request to the server so that the service can either refresh the token and repeat request, or let user know that he was logged out
See what i believe is the best way toachieve it is by adding a splashscreen to the app, and there you can divert logic if the token exists you can redirect to Homescreen or loginScreen.
like this :
in Splashscreen.js
componentDidMount(){
AsyncStorage.getItem('token') ? navigation.navigate('Home'):navigation.navigate('Login')
}
hope it helps.feel free for doubts

How to integrate squareup payment method to get the nonce in react-native app?

I am working on the latest version of React-native. I cannot find any documentation to get the card nonce using the application_id and location_id of SquareUp.
Please suggest me how to integrate this payment method with React-Native application.
Also, suggest me package works best for this.
Use this: https://developer.squareup.com/docs/payment-form/payment-form-walkthrough
up to step 1.3 to generate the nonce in html
Host this page on github pages and force it to server over https (http wont work with square)
Embed your github page in WebView React Native or Expo. Retrieve the nonce from WebView and pass it to your API where the rest can be taken care of with the square api.
In the Quick-Start you'll find the method onCardNonceRequestSuccess(cardDetails) which is the callback for returning your information from Square. On that cardDetails parameter you'll find a key "nonce" that will contain your nonce that you need to send to your back end for processing.
async onCardNonceRequestSuccess(cardDetails) {
if (this.chargeServerHostIsSet()) {
try {
await chargeCardNonce(cardDetails.nonce);
SQIPCardEntry.completeCardEntry(() => {
showAlert('Your order was successful',
'Go to your Square dashbord to see this order reflected in the sales tab.');
});
} catch (error) {
SQIPCardEntry.showCardNonceProcessingError(error.message);
}
} else {
SQIPCardEntry.completeCardEntry(() => {
printCurlCommand(cardDetails.nonce, SQUARE_APP_ID);
showAlert(
'Nonce generated but not charged',
'Check your console for a CURL command to charge the nonce, or replace CHARGE_SERVER_HOST with your server host.',
);
});
}
}
Link to repo of above code
The example application should show most of what is necessary for integrating into a React Native application. The main piece that you need to change is the chargeCardNonce() function found here to POST that nonce to your backend.

instagram api login with two-factor authentication

I'm using Instagram API for authentication in my app. the API works fine but when a user is using two-factor authentication the redirect_uri doesn't work and user redirected to the Instagram main page instead of the correct URL (my app login URL). I don't know how should I handle this and couldn't find any good answer. please help me
Note: this scenario happens for the first time and when Instagram's login session is available in browser user logged in correctly.
Not sure if this is still helpful. But I implemented the following on React Native WebView component and resolved Instagram's clear misstep.
Note - A more robust solution would be for Instagram to actually solve the bug.
As props on WebView:
source={{ uri: this.state.uri }}
onNavigationStateChange={this._onNavigationStateChange}
The handling method:
_onNavigationStateChange(webViewState){
const url = webViewState.url || ''
if(url.includes('challenge')){
this.setState({challenged: true})
}
if(url === 'https://www.instagram.com/' && this.state.challenged){
this.setState({
uri: `${URI}&indifferent_query_param=${(new Date).getTime()}`
})
}
}
The handling method forces rerender of WebView and sends the user to the "authorize" page. Depending on your platform of implementation, you could apply something similar to the above.