I have 2 amplify webapps and I want that both are using the same AWS backend. So i followed the instructions on https://docs.amplify.aws/cli/teams/multi-frontend/#workflow. App A has the full amplify backend src and App B shall use these too. So I run on App B.
amplify pull
>Amplify AppID found: df4xxxxxxx. Amplify App name is: XXXXX
>Backend environment dev found in Amplify Console app: XXXXX
Seems to work.
But when I now try to make an api call via:
AWS_API = 'api_name_on_aws';
async getUserInfosByUsername(username) {
var userInfos;
await API.get(this.AWS_API, `/users/infos/testuser`,
{
headers: {},
response: true,
body: {},
queryStringParameters: {},
})
.then((response) => {
userInfos = response;
})
.catch((error) => {
console.log(error.response);
});
return userInfos;
}
then no api request will send. (I can see within the google chrome dev console/network that no request is send).
The "request" method is just return "undefined" and thats all... On App A everything is working fine.
Did I miss something? Should I do something else that App B can use the API of APP A?
Related
My project is react native app that uses aws amplify and a rest api through api gateway. i am trying to add an item into my dynamoDB table by calling an API request like so :
const createItemDB = async () => {
API.post("nutritionAPI", "/items", {
body: {
userID: "authenticated user 1 ",
dateID: "1-28-2023",
},
headers: {
Authorization: `Bearer ${(await Auth.currentSession())
.getIdToken()
.getJwtToken()}`,
},
})
};
But this gets the error "request failed with 403 at node_modules\axios\lib\helpers\cookies.js:null in write" Prior to calling createItemDB, i authenticated myself as an "end-user" by Auth.signIn and each time i restart the app, I am still authenticated through my function below
const loadApp = async () =>{
await Auth.currentAuthenticatedUser()
.then(user=>{
console.log("successfully authd" + user)
})
.catch(()=>{
console.log("error signing in")
})
}
So I know i am authenticated. Im new to aws services, and im unsure how to configure the api gateway correctly. the only way to add an item to dynamodb is if I remove the header in my createItemDB call which means any unauthenticated user can add to my dynamodb? I tried to enable CORS inside api gateway but it still doesnt work
I configured and initialized AWS Amplify for my ReactNative/Expo app and added a REST Api. Im new to AWS in general, but im assuming that once I add the API, my project is populated with amplify/backend folders and files and is ready for consumption.
So i tried to create a simple post request to create an item in my DynamoDB table with
import { Amplify, API } from "aws-amplify";
import awsconfig from "./src/aws-exports";
Amplify.configure(awsconfig);
const enterData = async () => {
API.post("API", "/", {
body: {
dateID: "testing",
},
headers: {
Authorization: `Bearer ${(await Auth.currentSession())
.getIdToken()
.getJwtToken()}`
}
})
.then((result) => {
// console.log(JSON.parse(result));
})
.catch((err) => {
console.log(err);
});
};
const signIn = async () => {
Auth.signIn('test#test.com', 'testpassword')
.then((data) => {
console.log(data)
enterData() //enterData is attempted after signin is confirmed.
})
.catch((err) => {
console.log(err)
})
}
signIn()
I did not touch anything else in my project folder besides including the above in my App.tsx because im unsure if i need to and where. I got a 403 error code and it "points" to the axios package but im not sure if issue is related to aws integration.
I configured the REST Api with restricted access where Authenticated users are allowed to CRUD, and guests are allowed to Read. How could I even check if I am considered an "Authorized User" .
Yes, AWS Amplify API category uses Axios under the hood so axios is related to your problem.
Probably you get 403 because you didn't authorized, for Rest API's you need to set authorization headers,
I don't know how is your config but you can take help from this page. Please review the "Define Authorization Rules" section under the API(REST) section.
https://docs.amplify.aws/lib/restapi/authz/q/platform/js/#customizing-http-request-headers
To check authorization methods, you can use "Auth" class like that also you can see auth class usage in the above link.
import { Amplify, API, Auth } from "aws-amplify";
https://aws-amplify.github.io/amplify-js/api/classes/authclass.html
I'm just now diving into Cognito. The AWS setup has been fairly straight-forward, easy.
We have a variety of apps, webapps, and services and we'd like those to make use of the Cognito service. I've experience setting up similar with Auth0, but because we've been leveraging a number of Amazon Web Services, it really makes sense to use Cognito as well.
Everywhere I look, every guide eventually references Amplify client-side library and cli. We have existing apps and services, and really don't want to change tooling or import anything unnecessary to add bloat and complexity. Is there a way to use Cognito service without Amplify libraries? Is there a lightweight Cognito-only client library for interfacing with the Cognito service, authentication-and-authorization flow?
Update 03 Dec 2021
After re:Invent 2021, "Amplify Admin UI" was renamed to "Amplify Studio". With extra powers now:
automatically translates designs made in Figma to human-readable React UI component code
https://aws.amazon.com/blogs/mobile/aws-amplify-studio-figma-to-fullstack-react-app-with-minimal-programming/
===============
Original Answer
To start, I want to clarify that "Amplify" is an umbrella term for multiple things. We have:
Amplify Libraries (UI/JS)
Amplify CLI (to create cloud-native applications)
Amplify Console (ci/cd and hosting for full-stack web apps)
Amplify Admin UI (UI to create and configure full-stack web apps)
You can check the homepage for more clarification - https://docs.amplify.aws/
Is there a lightweight Cognito-only client library for interfacing with the Cognito service, authentication-and-authorization flow?
Behind the scenes, Amplify uses amazon-cognito-identity-js library to interface with Amazon Cognito. You can install that directly via npm install amazon-cognito-identity-js.
The source code has been moved to the Amplify Libraries (e.g. amplify-js) repository. Once again, is part of the "Amplify" umbrella under the first category "Amplify Libraries".
Is there a way to use Cognito service without Amplify libraries?
Another approach that you can do, is to use Amazon Cognito as an OAuth server. When you create an Amazon Cognito Hosted UI Domain, it provides you an OAuth 2.0 compliant authorization server.
You can create your own API/Backend for Signup/Login endpoints and exchange tokens/credentials with the Amazon Cognito OAuth server without using aws-sdk or any 3rd party dependency library.
I wrote a walkthrough example, how to configure your User Pool, endpoints that you need to talk to using Node.js, you can find it here: https://github.com/oieduardorabelo/node-amazon-cognito-oauth
You can follow the same idea for any other language.
As mentioned by #oieduardorabelo, you can simply install 'amazon-cognito-identity-js' where you can also find well done examples on npm.
Here is my test code to easily understand this lib. You must have already built the infrastructure on AWS (userPool, userClient and add a new user to test sign in - in my case the user has to change the password on first login so I added this use case on my script):
import * as AmazonCognitoIdentity from 'amazon-cognito-identity-js';
var authenticationData = {
Username: 'email',
Password: 'password',
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = {
UserPoolId: 'us-east-1_userpoolid',
ClientId: '26pjexamplejpkvt'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var cognitoUser = userPool.getCurrentUser();
console.log(cognitoUser);
if (!cognitoUser) {
var userData = {
Username: authenticationData.Username,
Pool: userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken();
var idToken = result.idToken.jwtToken;
console.log('Success', accessToken, idToken);
},
newPasswordRequired: function (userAttributes, requiredAttributes) {
delete userAttributes.email_verified;
cognitoUser.completeNewPasswordChallenge('DemoPassword1!', userAttributes, {
onSuccess: (data) => {
console.log(data);
},
onFailure: function (err) {
alert(err);
}
});
},
onFailure: function (err) {
alert(err);
},
});
}
If someone is interested in setup this test project from scratch run:
npm init -y
npm i -D webpack webpack-cli
npm i amazon-cognito-identity-js
in webpack.config.js:
var path = require('path');
module.exports = {
entry: './src/app.js',
mode: 'development',
output: {
path: path.resolve(__dirname, "dist"),
filename: 'main.js',
}
}
Create a new file in ./src/app.js where add the previous amazonCognitoIdentity code with the right AWS info ref and create ./dist/index.html whith:
...
<body>
<script src="main.js"></script>
</body>
in package.json add script "watch":
...
"scripts": {
"watch": "webpack --watch",
}
Finally run it:
npm run watch
and open the index.html directly on the browser with dev console as well.
Hopefully useful for someone.
As a result of research on the topic of using Amazon Cognito without Amplify in React, I came across such a sandbox. Switching from router 5 to router 6 probably won't be a problem. The main gold here is this hook. The rest of the implementation can be found in the sandbox: https://codesandbox.io/s/cognito-forked-f02htu
const Pool_Data = {
UserPoolId: "xxx",
ClientId: "yyy"
};
export default function useHandler() {
const [state, setstate] = useState({
loading: false,
isAuthenticated: false
});
const { loading, isAuthenticated } = state;
const userPool = new CognitoUserPool(Pool_Data);
const getAuthenticatedUser = useCallback(() => {
return userPool.getCurrentUser();
}, []);
console.log(getAuthenticatedUser());
useEffect(() => {
getAuthenticatedUser();
}, [getAuthenticatedUser]);
const signOut = () => {
return userPool.getCurrentUser()?.signOut();
};
console.log("I am here", getAuthenticatedUser()?.getUsername());
return {
loading,
isAuthenticated,
userPool,
getAuthenticatedUser,
signOut
};
}
I wrote an article a couple of years ago explaining how to do this.
The article talks about Amplify but as was mentioned in another response, that's more of an umbrella term, in the article we are using mostly UI components provided by the Amplify project.
you can find it here: https://medium.com/#mim3dot/aws-amplify-cognito-part-2-ui-components-935876fabad3
I have created a project in express
const express = require('express');
const app = express();
const PORT = 5555;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
app.get('/tr', (req, res, next) => {
res.json({ status: 200, data: 'tr' })
});
app.get('/po', (req, res, next) => {
res.json({ status: 200, data: 'po' })
});
module.exports = {
app
};
deployed on cloud function with name my-transaction
and i am scheduling with google clound giving the url like
http://url/my-transaction/po
When I deployed without authentiation scheduler runs job success, but when I do with authentication it fails.
similary if i create a sample project like below
exports.helloHttp = (req, res) => {
res.json({ status: 200, data: 'test hello' })
};
and deploy similary configuring same as above with authentication it works.
only differce is in last function name is similar to entry point means
while above entry point is app with different end points.
any help,
appreciated
Thanks
This is because you need to add auth information to your http requests on cloud Scheduler
First you need to create a service account with the role Cloud Functions Invoker
when you have created the service account, you can see that has a email associated fro example:
cfinvoker#fakeproject.iam.gserviceaccount.com
After that you can create a new scheduler job with auth information by following these steps:
Select target http
Write the url (cloud function url)
Click on "show more"
Select Auth header > Add OIDC token
Write the full email address of the service account
This new job scheduler will be send the http request with the auth infromation to execute successfully your cloud function.
I am using AWS Cognito for Authentication using user pools and I have all my APIs configured on the API gateway. I directly hit cognito from the Angular client, store the tokens returned by Cognito in local storage and use them in subsequent calls.
The problem however is, if the token I send from Angular has expired the Cognito authentication fails and no Integration backend is hit in this case. As a result, I am getting a 401 error in Chrome.
The interesting thing however is that this 401 code is not available to me in the HTTP response object that is passed to Angular. A default 0 code is received by the Angular and this seems to be the case with all the error code received from server (either cognito or backend).
I tried to explore around and found that the issue might be because the gateway is not sending proper CORS headers in the error cases. I have read following related docs but unfortunately I couldn't find out a way to resolve the issue.
Can someone suggest a solution to this.
Edit: I also read somewhere that it is a known AWS issue. Is that the case ?
You can manage the Cognito session before making the call to the API Gateway.
In the example below, the getSession method has a callback that prints out any error messages to the console, and returns.
////// Cognito.js
import {
CognitoUserPool,
CookieStorage
} from 'amazon-cognito-identity-js'
import config from '../config'
const cookieSettings = {
domain: '.xxxxxxxxxxx.com',
secure: true
}
export default {
cookieSettings,
pool: new CognitoUserPool({
UserPoolId: config.UserPoolId,
ClientId: config.ClientId,
Storage: new CookieStorage(cookieSettings)
})
}
//////
////// actions.js
import Cognito from './Cognito'
export function fetchUser() {
// get cognito user cookies
const cognitoUser = Cognito.pool.getCurrentUser()
if (cognitoUser != null) {
// try to get session from cognito
cognitoUser.getSession(function(err, session) {
if (err) {
console.log(err)
return;
}
fetch('https://api-gateway-url', {
headers: {
Authorization: 'Bearer ' + session.getAccessToken().getJwtToken(),
}
})
.then(response => response.json())
.then(json => console.log(json))
})
}
}