Invoke Lambda function from Amplify-generated React App without using API Gateway - reactjs

I used Amplify to generate a static website and the underlying React app. Initially I also generated an API endpoint but, because my lambda function may run over the API Gateway timeout limit (29 seconds), I need to invoke the lambda function directly from the generated React App, instead of going through API Gateway.
The code looks as follows, for the React page to authenticate using Cognito:
import Auth from '#aws-amplify/auth';
import { withAuthenticator } from 'aws-amplify-react';
import awsconfig from './aws-exports';
Auth.configure(awsconfig);
The above lines wrap the App (root) object and work as advertised. But since I do not want to use the API Gateway, how do I invoke the AWS Lambda function directly from React App?
The answers I could find talk about importing AWS etc, which seems to be in conflict with what we are trying to do here. I need to use the authenticated connection (which already works using the above code) when invoking lambda, so I cannot use generic invocation given in this example.
The Invoke API does not provide any examples as well.
Any advice is appreciated.

Note: if you do not need a response after your long running lambda, then consider API Gateways' Asynchronous Invocation
Amplify calls this approach "working with service objects".
To do this you'll have to ensure that the role Cognito gives your authenticated users includes permissions for lambda:invoke as well as any additional permissions needed within the function. I'll assume you can do that for now, however you can see the Role-Based Access Control documentation, or ask another question if not.
To access these roles within Amplify you need to use the Auth.currentCredentials function, which returns a promise with a credentials object, which can then be used on an aws-sdk client.
For example:
import Auth from '#aws-amplify/auth';
import Lambda from 'aws-sdk/clients/lambda'; // npm install aws-sdk
Auth.currentCredentials()
.then(credentials => {
const lambda = new Lambda({
credentials: Auth.essentialCredentials(credentials)
});
return lambda.invoke({
FunctionName: 'my-function',
Payload: JSON.stringify({ hello: world }),
});
})
You can see the full documentation for invoking lambdas on the AWS-SDK javascript documentation.
However you should be aware that the payload from API Gateway is constructed by AWS and includes much more information than just the body that the endpoint was called with, however when you invoke directly, all you'll get is the payload, so you'll have to build that payload object accordingly.

Related

401 Unauthorized calling my Azure Rest API

I have a Rest API using controllers, etc, hosted in Azure that has been working for some time. I want to secure the various methods. I added the API App (.NET core) to the App Registrations, and also added the javascript client app to App Registrations. I believe I'm initializing everything in startup.cs in the REST Api OK. I added [Authorize] to one of the methods. I used a simple javascript example which calls myMSALObj.loginPopup, and gets back a token which I then add to the Authorization header and make a fetch call. When I call, I see HTTP Error 401.0 - Unauthorized in the log stream for my App Service.
Any ideas how I can troubleshoot this to get more specifics about what is wrong?
Also, a related question: in App Registrations, Api Permissions, how does one correlate the API permission name with the method in the controller?
Add this in front of the method in the controller
[AuthorizeForScopes(Scopes = new[] { "My.Scope" })]

Running login mutation in utility function instead of component

This question is probably a sign of my misunderstanding of the philosophy of Apollo/React/GraphQL, but I'm a bit stuck here.
I am writing the authentication logic for my single page app. I have a backend with a GraphQL API that authenticates users by returning a JWT access/refresh token pair. So, to login, I need to send a mutation to the GraphQL endpoint from my app.
My frontend uses Apollo Client. Now I understand I can run a mutation with useMutation, I understand how this works. But I also know that React Hooks need to be specified at the top of a component. I could have this useMutation call in a login component, but this feels like bad encapsulation.
The problem is that I want to have a separate login utility function that takes a username and password, sends the login mutation request to the backend, and returns the response.
From my understanding, I cannot use useMutation here, as I'm not in a React component. I can of course write a fetch call myself:
export const login = (username, password) => {
return fetch("/api", {
method: "POST",
...
}
but this feels unclean when I'm working within the Apollo Client ecosystem. Am I missing something, should I just roll ahead with these manual fetch calls, or am I misunderstanding the whole philosophy here?
As long as you have access to an instance of ApolloClient, you can call the mutate method on it directly. You can also pass the client in as a parameter, in which case you might find it helpful get the client instance through the useApolloClient hook. Alternatively, you can just export the client and then import it directly inside your function. Whatever approach you take, just make sure you're using the same instance of ApolloClient that you use elsewhere in your app to ensure you're updating the correct cache.
const client = new ApolloClient({...})
...
const { data, errors } = await client.mutate({...})

Reading returned data from Stripe OAuth Redirect-URI (Stripe OAuth, Firebase back-end, React front-end)

I am completely stuck trying to figure out how to allow users to sign up a "Connected Account" via Stripe OAuth steps for my website. (I'm building a marketplace website with React front-end, Firebase back-end, and Stripe to handle payments).
Some guides I have been trying to use to help guide me are as follows:
(1) https://stripe.com/docs/connect/collect-then-transfer-guide : I am stuck on this guide at step 2.2. However this guide is not as helpful since I am using Firebase as my backend.
(2) https://medium.com/#c.nwaugha/integrate-stripe-payment-with-firebase-cloud-functions-part-2-e381babd39bc : I am stuck on this guide at around 1/3rd up the page (see yellow text of image below)
Unfortunately I'm not sure what my Stripe Redirect URI should be. I currently have it set to something similiar to "https:MyWebsiteName.com/oauth_redirect" on my Stripe settings, however this link doesn't have a React front-end yet and am not sure what code it should contain.
Simply put, how can I continue the OAuth setup process and pull the data from a returned URL. Any clarity is greatly appreciated. (PS: I did look into "Regex" as the guide suggests, but am unable to find anything that appears to be useful for this case).
UPDATE and PARSING URL SOLUTION
Thanks to hmunoz's advice, I was able to parse through the returned URL and capture the stripe OAuth Authorization Code in a string. (Please see the code below).
This is returned when this page "https://.../oauth_return" URI is reached after the user finishes the OAuth forms on stripe.
import React from 'react';
import queryString from 'query-string'; //this is a 3rd party library that is used to parse through the Redirect URL returned from Stripe.
const oauth_redirect = () => {
//Parsing over URL
const value=queryString.parse(window.location.search);
//Retrieves the "code" value.
const code=value.code;
console.log('code:', code)
//Retrieves the "state" value.
const state=value.state;
console.log('state:', state)
... //(I'm not sure how to pass these strings into a Firebase HTTP function).
}
export default (oauth_redirect)
CURRENT PROBLEM; BUILDING FIREBASE HTTP FUNCTION USING JAVASCRIPT
I am trying to build a Firebase HTTP function that uses the POST method, to return this Authorization Code. I have a function inside "index.js" of the functions/src directory of this react website. Unfortunately all of the guides on this subject have the firebase function is .typescript and I am using .javascript. Any clarity on how build this HTTP function in .javascript would be greatly appreciated!!!
Please note: I clarified the question a bit in the following post :Returning Authorization Code to Stripe using Firebase HTTP Function (Firebase, Stripe OAuth, React (JSX) frontend)
The redirect_uri in this case is the final page that you want your user to land on, once they have authenticated via Stripe.
This would have to be a web page of yours, say https://your-website.com/oauth-complete
Once on this page, your React code needs to grab the URL parameter like code: ac_123 which is the authorization code, and call a Firebase function with that authorization code.
Your Firebase function will complete the OAuth connection to this Connect account by consuming the OAuth token.
These two steps are described here: https://stripe.com/docs/connect/oauth-standard-accounts#redirected
Not sure if I've arrived too late. You can start simple uncommeting the example from the index.js in /functions.
You can test running firebase emulators:start from your terminal.
It might start in the localhost:5001/project-name/zone/newFunction
exports.newFunction = functions.https.onRequest( (req, res) => {
// your logic code here
}

AWS Amplify Gateway REST - React (good) vs React Native (403)

I am looking to create one API via AWS Amplify that I can query/post to from React and React Native. I set up the API and Lambdas via serverless, and a user pool manually via the Cognito console, with two separate app clients for each platform. The React setup went swimmingly, all gets/posts/puts to the API work as expected.
React-Native has proven to be a little more hairy. I manually configured Amplify with the same values as in the React project, except for APP_CLIENT_ID, to match the app client in the user pool in Cognito.
The Auth calls (SignIn, SignUp) all work fine, so the config is at least partly ok. But the same REST API calls that work perfectly in React respond with 403s in Native, Missing Authentication Token. (Same user). I poked around the documentation and saw that I may need to use a custom_header in my Native config:
Amplify.configure({
API: {
endpoints: [
{
name: 'testapi',
endpoint: config.apiGateway.URL,
region: config.apiGateway.REGION,
custom_header: async () => {
return {
Authorization: (await Auth.currentSession()).idToken.jwtToken
};
}
}
]
}
});
This clears the Missing Authentication Token error, but now I get:
Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header.
I compared the full requests via the Chrome console, and it looks like the Authorization header in React is correctly generated via Amplify, with Credential, Signature, SignedHeader, etc. It looks vastly different in Native, as the custom_header change above just sets the Authorization header to a jwtToken.

How can I mock the results of the GMail API?

We are using the GMail API and developing an application on top of it. Ideally I would like to have some golden emails to test the analytics engine against. This way I can develop the analytics engine without having to worry about fetching the emails and hence without a network connection. What is the best way to achieve this? I noticed that App Engine (which we use) now allows you to mock DataStore/memcache etc. and run nosetests, but I don't know how to do this across local appserver restarts.
The Mock class provided by googleapis/google-api-python-client looks like a good candidate for your use case.
from googleapiclient.discovery import build
from googleapiclient.http import HttpMock
mock = HttpMock('mock-email-list.json', {'status': '200'})
gmail = build('gmail', 'v1', http=mock)
response = gmail.users().messages().list(userId='me').execute()
print(response)
Where mock-email-list.json content is of the form
{
"messages":[
{
"id":"abcd",
"threadId":"abcd"
},
{
"id":"efgh",
"threadId":"abcd"
},
],
"resultSizeEstimate":2
}
As a side note, after your test has run, you can also check what url the mock has been used for (by the gmail client):
assert mock.uri == 'https://gmail.googleapis.com/gmail/v1/users/me/messages?alt=json'
The Gmail API nor the client libraries provide special functionality for mocking email fetching. You'll need to build out the mocks on your own.

Resources