Plaid Transaction Webhooks Not Firing When Using React Plaid Link - reactjs

I am using ReactPlaidLink to build an app that retrieves users transaction history and displays it on the front end. My goal right now is to get the webhooks to fire at the specified endpoint. I set up an endpoint to listen for requests using both webhook.site and requestbin, and have not seen a request come through. I have specified the endpoint in both the React-Plaid. From what I understand form the documentation, specifying a webhook paramater is all that's necessary for the webhooks to fire to the right endpoint. I am definitely a novice when it comes to webhooks, I hope I'm not missing something super obvious. Would appreciate any insight you can offer.
<PlaidLinkButton
buttonProps={{
className:
"btn btn-large waves-effect waves-light hoverable blue accent-3 main-btn"
}}
plaidLinkProps={{
clientName: "BankLinker",
key:" ",
token: "my-token",
env: "sandbox",
product: ["transactions"],
webhook: 'https://webhook.site/465538a7-f2a5-4d55-b017-db23b949ef91',
onSuccess: this.handleOnSuccess,
}}
onScriptLoad={() => this.setState({ loaded: true })}
>
Add Account
</PlaidLinkButton>```
and HandleSuccess
```handleOnSuccess = (token, metadata) => {
const { accounts } = this.props;
const plaidData = {
public_token: token,
metadata: metadata,
accounts: accounts,
// webhook: "https://webhook.site/465538a7-f2a5-4d55-b017-db23b949ef91",
};
this.props.addAccount(plaidData);
};

I'm not an expert on the RN SDK, but on a quick glance I don't see anything glaringly, obviously wrong here. Can you confirm that you can go through the Link flow, wait a few seconds, and then call the /transactions/get endpoint, and successfully get data back from it? That will help confirm that the issue is with webhooks and not some other part of the process.

Related

Extra 'Undefined' parameter is adding to the api url for deleting request

I am implementing deleting record functionality where on clicking on the trash icon, the record with that id will be deleted from database. I'm using API endpoint, and mentioned it correctly in resource.js file as well.
The problem is that whenever I click on trash icon for deleting that row, and extra undefined parameter is added to the endpoint. Because of this, it's not able to reach the correct api endpoint and not able to delete the record.
Can anyone please provide any suggestion/input regarding this? I'm new to web development and not able to proceed further.
These are the code snippets I'm using:
Delete function triggering from trash icon
async onDelete(data) {
console.log(data.leasing_agent_id);
this.requestConfirmation({
confirmationMessage: `Are you sure you want to delete agent ${data.first_name} ${data.last_name}?`,
confirmBtnText: 'Delete',
cancelBtnText: 'Go Back',
confirmationType: 'warning',
}).then(confirmed =>
confirmed
? this.$calendarDataProvider
.delete('calendarDeleteLeasingAgentsById', {
leasing_agent_id: data.leasing_agent_id,
})
.then(res => {
this.originalData = this.data = res;
this.$refs.vuetable.refresh();
this.notifySuccess(`Agent ${data.first_name} ${data.last_name}has been deleted`);
})
.catch(error => this.notifyError(error.message))
: null
);
},
Button triggering the onDelete() function:
<button
class="button"
#click="onDelete(props.rowData)"
>
<icon
name="trash"
class="w-5 h-5 mt-2 ml-2 text-red-500"
/>
</button>
All the above code is in my index.vue file.The resource.js file is like this:
// Get leasing agents by customer id
calendarGetLeasingAgents: '/leasing-agents/customers/{customer_id}',
// Get leasing agents by id
calendarGetLeasingAgentsById: '/leasing-agents/{leasing_agent_id}',
// Save leasing agent
calendarSaveLeasingAgents: '/leasing-agents',
//Delete leasing agent
calendarDeleteLeasingAgentsById: '/leasing-agents/{leasing_agent_id}',
Also, attaching a screenshot of how error looks like:
https://drive.google.com/file/d/1aMKjLRQJGG4Eg-YsPRa6p73gs4mPIkcg/view?usp=sharing
Any input would be appreciated.

Next Js Firebase Recaptcha V3 verification

I'm very confused about the Recaptcha V3 implementation and it is not clear to me if actually need to implement it on my website or if initializing Appcheck with my Recaptcha V3 credentials is enough: Appcheck does successfully initialize and I have enforced firestore and the cloud storage to use it.
I don't want bots to create infinite accounts on my website and raise like crazy my costs so I looked into implementing Recaptcha on forms: the developer documentation is a joke (https://developers.google.com/recaptcha/docs/v3) as it is not explained how to verify the token which is returned
I saw an old article from 2017 telling you to use Cloud Functions (which may take up to 10-12 seconds to fire up in case of cold-start) but this sounds really far-fetched and 5 years later I hope we have a better solution: https://firebase.googleblog.com/2017/08/guard-your-web-content-from-abuse-with.html
Am I overthinking this? Would Appcheck protect my app from people abusing my contact form and sign up section? If this is not enough, how can I implement Recaptcha V3 with React and Firebase?
I am using Next JS and so far my code looks something like this (where I replaced my publishable key "mySyteKey"):
import Script from "next/script";
export default function TestRecaptcha() {
const handleSubmit = (e) => {
e.preventDefault();
grecaptcha.ready(function () {
grecaptcha.execute('mySiteKey', {action: 'submit'}).then(function (token) {
// How the hell do I verify this token!?
console.log(token)
}), error =>{
console.log(error.message)
}
});
}
return (
<div>
<Script src="https://www.google.com/recaptcha/api.js?render=mySiteKey"
strategy="beforeInteractive"/>
<form onSubmit={(e) => handleSubmit(e)}>
<button
type="submit">
Submit
</button>
</form>
</div>
)
}

How do you "Sign In with Google" with NextJS and Firebase Auth on Safari

I'm using:
firebase: ^8.6.8
next: ^11.0.1
react: ^17.0.2
When trying to sign in with Google on Safari, I get errors related to a Content Blocker with both signInWithPopUp and signInWithRedirect:
Content blocker prevented frame displaying https://my-site.com/page
from loading a resource from https://apis.google.com/js/api.js?onload=__iframefcb318667
Does anybody know how to handle this properly?
Thank you!
Okay, here is the solution I used:
Instead of using signInWithRedirect or signInWithPopup that seem to cause problem on Apple devices using Safari, I directly use [https://apis.google.com/js/platform.js] and then signInWithCredential using the googleUser.
I also used the package react-google-signin [https://www.npmjs.com/package/react-google-login] to simplify my code.
Step by step:
Enable Google Sign-in method on Firebase Console for Authentication
On the Credentials page of Google Cloud Platform [https://console.developers.google.com/apis/credentials], choose your project and under OAuth 2.0 Client IDs get the Client Id.
Save the Client ID as an environment variable NEXT_PUBLIC_GOOGLE_CLIENT_ID in your Project Settings on Vercel.
In your _document.tsx add the https://apis.google.com/js/platform.js script and needed meta data:
<meta name="google-signin-client_id" content={process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID}></meta>
<meta name="google-signin-cookiepolicy" content="single_host_origin"></meta>
<meta name="google-signin-scope" content="profile email"></meta>
<script src="https://apis.google.com/js/platform.js" async defer></script>
Define your Google Sign in button:
const GoogleButton: FC<GoogleButtonProps> = ({onSuccess, onFailure}) => {
const onSignInFailure = (failure: any) => {
console.error('FAILURE: ', failure);
onFailure(...);
};
const onSignIn = (googleUser: any) => {
signInWithGoogleUser(googleUser)
.then(onSuccess)
.catch(onFailure);
}
return (
<GoogleLogin
render={(renderProps) => (
<button
onClick={renderProps.onClick}
disabled={renderProps.disabled}>
This is my custom Google button
</button>
)}
clientId={process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!}
buttonText="Login"
onSuccess={onSignIn}
onFailure={onSignInFailed}
cookiePolicy={'single_host_origin'}
prompt="select_account"
/>
);
};
I specified prompt="select_account" to be sure it prompt the user for the account selection even if hse is already logged in.
Then, inside signInWithGoogleUser, is use signInWithCredential to use the googleUser to authentify on Firebase Auth:
export const signInWithGoogleUser = (googleUser: any) => {
const auth = firebase.auth();
const provider = firebase.auth.GoogleAuthProvider;
const credential = provider.credential(googleUser.getAuthResponse().id_token);
return auth.signInWithCredential(credential);
};
NOTES
a. My project is running on Vercel [https://vercel.com/] with the Database (Firestore) and Authentication on Firebase [https://firebase.com]. You will have to adapt my solution if you use another stack.
b. With this, it works on almost all iPhones and Mac computers. In case it still fails, it is due to an installed content/cookie blocker and I display an error message asking the visitor to reactivate cookies or register using email and password.
c. I simplified a bit the code to have a more condensed answer.

Graph API with ASP.NET Core Blazor WebAssembly

I would like to get information from Microsoft graph web API. I followed these instructions:
https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/graph-api?view=aspnetcore-5.0
The problem is that the variable "token" in the AuthenticateRequestAsync method is always null. It means that the Blazor app does not get the token.
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
var result = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions()
{
Scopes = new[] { "https://graph.microsoft.com/User.Read" }
});
if (result.TryGetToken(out var token))
{
request.Headers.Authorization ??= new AuthenticationHeaderValue(
"Bearer", token.Value);
}
}
The Program.cs has the following code:
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddMsalAuthentication<RemoteAuthenticationState, RemoteUserAccount>(options =>
{
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});
builder.Services.AddGraphClient("https://graph.microsoft.com/User.Read");
In Index.razor I just add two lines of code I OnInitializedAsync method
var request = GraphClient.Me.Request();
user = await request.GetAsync();
I spent a lot of time to figure out what is the main issue but without success. I will appreciate any help.
Please imagine the single-page website. Usually, this kind of page has a "contact us" tab where is the contact form. If the user fills up the contact form then data have to be somehow sent to us. For this purpose, I tried to use MS graph API. When the user clicks the submit button, in the background the registration to my account will be created and an email will be sent to me. It means that the user is not aware of any registration procedure. – Samo Simoncic
For your app to be able to create users in a tenant, it needs to use an app only flow which requires a secret. We do not advise exposing app only flows of this nature, which can easily be exploited to create bogus users or overwhelm your tenant, open to the general public.
The best approach would be to take this registrations in a local DB, and then have a daemon app process them behind the scenes. Here is the sample where daemon console application is calling Microsoft Graph.
Not sure about the cause of the issue.
But I can make it work with the following code and configuration:
Program.cs
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
// Adds the Microsoft graph client (Graph SDK) support for this app.
builder.Services.AddMicrosoftGraphClient("https://graph.microsoft.com/User.Read");
// Integrates authentication with the MSAL library
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
});
await builder.Build().RunAsync();
}
appsettings.json
{
"AzureAd": {
"Authority": "https://login.microsoftonline.com/exxxxx4e-bd27-40d5-8459-230ba2xxxxxb",
"ClientId": "7xxxxxx8-88b3-4c02-a2f8-0a890xxxxxx5",
"CallbackPath": "/signin-oidc",
"ValidateAuthority": "true",
"DefaultScopes": [
"openid",
"profile"
]
}
}
You can refer to the configuration and sample code here.
I have cloned your repo from the GitHub URL you posted in the comments.
There is no issue with the code to fetch the data from the Microsoft Graph API, the problem is that you have written the code of calling the API when the apps shows the index component before even the user logs in, you have to check if the user is logged in first and add a login button to the UI or you can add [Authorize] to the index page so it will redirect the user to Login before it shows the component and make the API and to implement that make sure to add the CascadingAuthenticationState and AuthorizeView to your App.razor as following
<CascadingAuthenticationState>
<Router AppAssembly="#typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="#routeData" DefaultLayout="#typeof(MainLayout)">
<NotAuthorized>
#if (!context.User.Identity.IsAuthenticated)
{
<a class="btn btn-success" href="/authentication/login">Login with Microsoft</a>
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="#typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
And then in your Index.razor add at the top the following line
#attribute [Authorize]
Then you launch the app if the user is not logged in, he/she will be asked to do so and then go to the Index component and make the API call which will succed then

Getting “TypeError: failed to fetch” when sending an email with SendGrid on ReactJS project

I am trying to send email with SendGrid in ReactJS project.
This is my componnet:
//Email.js
import React from 'react'
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'aaaaa#gmail.com',
from: 'bbbb#gmail.com',
subject: 'This is a test mail',
text: 'and easy to do anywhere, even with Node.js',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
sgMail.send(msg).catch(error => {alert(error.toString()); });
export const Email= () => (
<h1>Email Sending Page</h1>
)
When I am trying to run the app with "npm start" on localhost, the email is not sent and I got the error message "TypeError: Failed to fetch".
But, if I am using this code:
//Email.js
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'aaaaa#gmail.com',
from: 'bbbb#gmail.com',
subject: 'This is a test mail',
text: 'and easy to do anywhere, even with Node.js',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
sgMail.send(msg)
and do this command: "node Email.js" the mail is sent. It works only this way and I cannot understand why.
I tried any solution that I could find but nothing works.
(I tried even to put the api_key hardcoded in the code just for the test and I got the same result).
EDIT
After looking around a bit I found out that you can't use Sendgrid to send email directly from the browser.
Sendgrid won't let you send an email directly using Javascript in the
browser.
You will need to have a server set-up and use the server to send the
email instead (using your favourite back-end framework/language,
Node.js, php, Java, etc.).
The steps for sending a mail will be similar to this:
Write email details in the React application
Send a POST request to
your server endpoint (for example, /sendemail) with the email data
(recipient, title, content, etc.) Receive Email data in the server and
send it to Sendgrid api Here is the official Sendgrid documentation
regarding their CORS policy:
https://sendgrid.com/docs/for-developers/sending-email/cors/
Source: React unable to send email with SendGrid
EDIT 2
If you want to implement Sendgrid without actually building and deploying a server, you can use a simple Firebase function which is free to host.
I know this may look intimidating but in reality its pretty easy. Also I just put this together real quick so if anything doesn't work out for you, shoot me a comment.
Follow steps 1-3 on the getting started page for firebase functions. It is pretty straightforward and you end up with the firebase tools CLI installed.
Navigate to the functions/ folder inside your project on the command line/terminal.
Install the Sendgrid and cors libraries in the functions folder
npm i #sendgrid/mail cors
Add your Sendgrid API key to your firebase environment with the following command in your project:
firebase functions:config:set sendgrid.key="THE API KEY"
Copy this into your functions/index.js file:
const functions = require("firebase-functions");
const cors = require("cors")({ origin: true });
const sgMail = require("#sendgrid/mail");
exports.sendEmail = functions.https.onRequest((req, res) => {
sgMail.setApiKey(functions.config().sendgrid.api);
return cors(req, res, () => {
const { msg } = req.body;
sgMail.send(msg).catch(error => {
alert(error.toString());
});
res.status(200).send(msg);
});
});
Save it and run firebase deploy --only functions on the command line. Your function should now be live at https://us-central1-<project-id>.cloudfunctions.net/sendEmail
Now change your React file to:
//Email.js
import React, { useEffect } from 'react'
export const Email= () => {
useEffect(() => {
const sendEmail = async() => {
const msg = {
to: 'aaaaa#gmail.com',
from: 'bbbb#gmail.com',
subject: 'This is a test mail',
text: 'and easy to do anywhere, even with Node.js',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
const response = await fetch(
'https://us-central1-FIREBASE-PROJECT-ID-HERE.cloudfunctions.net/sendEmail', {
method: 'POST',
body: JSON.stringify(msg),
headers: {
'Content-Type': 'application/json'
}
});
console.log("response", response);
}
sendEmail();
}, []);
return <h1>Email Sending Page</h1>
}
And thats it! You basically have a server side function without making a server and its free!
Feel free to ignore this if you don't feel like putting in the work but if you need any help, let me know.

Resources