Accessing AWS AppSync without using API Keys in React Native - amazon-web-services

In my React Native App I am using API Keys with AWS AppSync and I want to move to using Cognito or IAM but with no user sign in.
My React Native app that just uses AWS Appsync to read to and write from DyanmoDB.
I initially set up the app to use API keys as it was easier to understand and I'm now attempting to transition to using AWS Cognito or IAM.
To do this in my AWS Console I changed the "Appsync->MyAppAPI->Settings->Default authorisation mode"/"API-level" from "API key" to "AWS Identity and Access Management (IAM)".
I then created an Identity Pool and allowed "Enable access to unauthenticated identities".
My aws-exports file is
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_appsync_graphqlEndpoint": "https://xxxxx.appsync-api.eu-west-x.amazonaws.com/graphql",
"aws_appsync_region": "eu-west-X",
"aws_appsync_authenticationType": "AWS_IAM",
"aws_appsync_apiKey": "xxx-xxxxxxxxxxxxxxxxxxxxxxxxxx",
};
export default awsmobile;
In my App.js file I have attempted to get the identityPoolId to be used and I have created this:
Amplify.configure({
url: config.aws_appsync_graphqlEndpoint,
region: config.aws_appsync_region,
auth: {
type: config.aws_appsync_authenticationType,
apiKey: config.aws_appsync_apiKey,
region: 'eu-west-x',
identityPoolId: 'eu-west-x:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
}
})
When I use the app to read from DynamoDB I get this error
[WARN] 04:51.835 API - ensure credentials error, No Cognito Federated Identity pool provided
I then went back to the Cognito Manage Identity Pool page and changed my identity pool to use Cognito as an authentication source and provided a User Pool ID and an App client id. But I still get the same error.
I am fundamentally missunderstanding something, could you offer any insight?

Related

AWS Pinpoint updating user attributes when unauthenticated - security issue?

I'm looking at using AWS Pinpoint to send push notifications to my react native app. However it seems that unauthenticated users are able to update user attributes for any user they wish, ie there is no access control. I'm new to mobile development, but isn't putting stuff like that into the frontend a security issue? If it were a web application, people would be able to inspect network calls to obtain credentials and make any call they wish to updateEndpoint. Is this not applicable to mobile apps or am I misunderstanding something?
Details:
There's a step in the setup that says Edit the IAM policy document for unauthenticated identities to allow permissions for the mobiletargeting:PutEvents and mobiletargeting:UpdateEndpoint actions
And react native code snippet provided goes as follows:
import Analytics from '#aws-amplify/analytics';
import Auth from '#aws-amplify/auth';';
const amplifyConfig = {
Auth: {
identityPoolId: 'COGNITO_IDENTITY_POOL_ID',
region: 'ap-south-1'
}
}
//Initialize Amplify
Auth.configure(amplifyConfig);
const analyticsConfig = {
AWSPinpoint: {
// Amazon Pinpoint App Client ID
appId: 'cd73a57d200e49e2bc4b97d6ebf63cd4',
// Amazon service region
region: 'ap-south-1',
mandatorySignIn: false,
}
}
Analytics.configure(analyticsConfig)
Analytics.updateEndpoint({
attributes: {
interests: ['science', 'politics', 'travel'],
//..
},
userId: 'UserIdValue',
userAttributes: {
username: 'ilovethecloud'
}
});
I'm not sure if this will help,
But you have 2 IAM policies (in Cognito Identity-pool), 1 for authenticated users and 1 for unauth. users.
You should restrict the IAM policy for unauth users, so they can't edit other users info.
Also, the credentials that you are given by Cognito, are temporal, they expire (and get renewed by your react-native app), so in that way you are safe.

How to create custom user pool on cognito, and connect this to your application

I would like to use the out-of-the-box user account creation with cognito, and am able to do that. But I would like to add custom attributes.
Now, is there a way, using the terminal, that you can ask amplify to use the user pool you have created, instead of the default one that it generates for you?
Indeed, you do not have to create a Cognito User/Identity Pools when using AWS Amplify (simply, do not run amplify add auth).
And even if you have one created by default, you can still manually configure Amplify to use desired resources for authentication as:
Amplify.configure({
Auth: {
identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
region: 'XX-XXXX-X',
identityPoolRegion: 'XX-XXXX-X',
userPoolId: 'XX-XXXX-X_abcd1234',
userPoolWebClientId: 'a1b2c3d4e5f6g7h8i9j0k1l2m3',
mandatorySignIn: false
}
});
Just put the proper values of your project. For further options for manual configuration, you can have a glance at the Amplify Auth docs.

How can I access an AWS DynamoDB as a guest user?

I am using aws-amplify and aws-sdk in Angular JS/Typescript.
I can successfully access my AWS DynamoDB as an authenticated user.
I am also trying to add guest user access for a certain table in Dynamo, but I am struggling to understand how I would get a reference to the DynamoDB without any credentials.
My code looks like this at the moment
getDocumentClient() {
return Auth.currentCredentials()
.then(credentials => new AWS.DynamoDB.DocumentClient({ credentials: credentials }))
.catch(err => logger.debug('error getting document client', err));
How would I do something similar to get access to the DynamoDB as an unauthenticated guest user?
Cheers
Lee
Try makeUnauthenticatedRequest.
Here's an example with S3 - I've shown this because I know you can make requests to S3 from the AWS SDK as an unauthenticated user. I'm assuming that this will also work for DynamoDB but have not tested it.
var s3 = new AWS.S3();
var params = {
Bucket: 'mybucket'
};
s3.makeUnauthenticatedRequest('listObjects', params, callback);
The more strategic approach would be Amazon Cognito Identity Pools which support unauthenticated/guest identities. Cognito vends an identity and AWS credentials, and you can configure an IAM role allowing DynamoDB read access for unauthenticated identity types.
I think you can refer to what is mentioned in the blog post below.
https://aws.amazon.com/blogs/compute/using-amazon-api-gateway-as-a-proxy-for-dynamodb/
The basic idea is to use API Gateway as a proxy for DynamoDB API. Permission to access DynamoDB is granted to API Gateway via execution role, and API Gateway is configured to open to public. In doing so, the flow will be as follows:
Web Browser <----- HTTPS -----> API Gateway <----- AWS Service Proxy integration -----> DynamoDB

API gateway how to pass AWS IAM authorization from rest client

I am trying to test authenticated API gateway endpoint from rest client. How to I generate/set the "AWS_IAM" authorization headers when making the request ?
You can use Cognito with a "public" pool id, then attach role to the Cognito pool id, the role being accessing your API GATEWAY
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'REGION:YOUR_POOL_ID',
});
Use AWS STS to get temporary credentials with limited privileges. After that you can use API Gateway with AWS_IAM authentication
The generated SDK accepts AMI credentials, you have to initiate the client with the one you got from STS:
var apigClient = apigClientFactory.newClient({
accessKey: 'ACCESS_KEY',
secretKey: 'SECRET_KEY',
sessionToken: 'SESSION_TOKEN', //OPTIONAL: If you are using temporary credentials you must include the session token
region: 'eu-west-1' // OPTIONAL: The region where the API is deployed, by default this parameter is set to us-east-1
});
NB: Put strictly minimum roles on your pool, that is a publicly available id, every body can use it to get a temporary or a fixed (to track users across devices) user_/app_ id.
Update April 2016:
For Christine comment's: Documentation on how to use STS.
TL;DR: Basically after your Identity provider calls you back (Google, in my case), you will have a Token (OpenID, in my case), just feed it to STS:
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: 'arn:aws:iam::<AWS_ACCOUNT_ID>:role/<WEB_IDENTITY_ROLE_NAME>',
ProviderId: 'graph.facebook.com|www.amazon.com', // Omit this for Google
WebIdentityToken: ACCESS_TOKEN
});
You'd have to replicate API Gateway AWS v4 request signature logic to be able to do that. Ideally you should look at the the generated Javascript/Java SDK for your API to get an idea on how these request signatures get calculated. I suggest you turn the authentication off for your testing requests.

How can I call AssumeRoleWithWebIdentity to access Amazon DynamoDB?

Scenario:
I create an app on Amazon, and use Login with Amazon, which returns an "access_token". Then I run:
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: 'arn:aws:iam::416942672???:role/???_amazon_role',
ProviderId: 'www.amazon.com',
WebIdentityToken:"?????????"
});
AWS.config.region = 'us-west-2';
dynamodb = new AWS.DynamoDB() dynamodb.listTables({}, function a(error,data){
alert( "error: " + JSON.stringify(error) );
alert( JSON.stringify(data) );
});
When I later run the ListTable function it will return:
error: {"message":"Missing credentials in config","code":"SigningError","name":"SigningError","statusCode":403,"retryable":false}
I found it seems that I have to call AssumeRoleWithWebIdentity. But how can I call it in AWS SDK for JavaScript? Or is there any other process I missed?
The process of Getting Temporary Credentials indeed requires a call to AssumeRoleWithWebIdentity - this low level API call is implied in the higher level AWS SDK for JavaScript credentials provider call new AWS.WebIdentityCredentials() though, see e.g. Class: AWS.WebIdentityCredentials:
Represents credentials retrieved from STS Web Identity Federation
support.
By default this provider gets credentials using the
AWS.STS.assumeRoleWithWebIdentity() service operation. This operation
requires a RoleArn containing the ARN of the IAM trust policy for the
application for which credentials will be given. In addition, the
WebIdentityToken must be set to the token provided by the identity
provider. See constructor() for an example on creating a credentials
object with proper RoleArn and WebIdentityToken values.
Given the error message "Missing credentials in config", you are obviously passing an incorrect WebIdentityToken, which isn't a surprise given you just specified some ????????? placeholders ;) - since you already use Login with Amazon, which returns an access_token, you'll just need to pass the content of that ACCESS_TOKEN instead of those ????????? placeholders as value for WebIdentityToken and should be all set.
For other readers: Section 6. Putting it all together of Configuring Web Identity Federation in the Browser provides an example for retrieving the access token via Facebook Login. As noted there, Other identity providers will have a similar setup step that involves loading the respective SDK, logging in, and receiving an access token - in particular, how to handle Login with Amazon is documented in detail within Getting Started for Web.
Use AWS instance in this way:
var aws = AWS ;
var region = aws.config.region = 'us-east-1';
var cred = new aws.Credentials(<YOUR_ACCESS_KEY_ID>,
<YOUR_SECRET_ACCESS_KEY>, sessionToken = null);
To get ACCESS KEY ID and SECRET ACCESS_KEY go to:
AWS IAM>Users>Security Credentials>Access Keys
Now use aws instance for further operations.