I enabled access to unauthenticated identities to do some quick testing before integrating authentication. My configuration code is the following,
Amplify.configure({
Auth: {
identityPoolId: 'us-east-1:example',
region: 'us-east-1',
userPoolId: 'us-east-1_example',
userPoolWebClientId: 'us-east-1_example'
},
API: {
endpoints: [
{
name: "example-name",
endpoint: "https://example.execute-api.us-east-1.amazonaws.com/prod/example-path"
},
]
}
});
and my GET request code is the following,
example() {
const apiName = 'example-name';
const path = '/example-path';
API.get(apiName, path).then(response => {
console.log(response)
}).catch(error => {
console.log(error)
})
}
I followed everything on GitHub and my API gateway and Lambda functions are working correctly when I run a "test" and through postman. But on react-native it's giving me a 403 status code without any detailed explanation. Does this have to do with accessing using unauthenticated identity? Also, I used "example" in my code to hide my personal information, I typed in everything correctly since I'm not getting any syntax error (identity pool recognizes access every time I run it, but cloudWatch doesn't show any log of gateway access)
The Endpoint in Amplify.configure is the InvokeURL from API Gateway, you just need to include the stage (/prod in this case) and not the other routes. The other routes are just the path parameters for API.() calls.
Related
Situation:
I have a ReactJS web application that is deployed through AWS Amplify and uses Amplify Studio backend to handle authentication through Cognito services and aws-amplify sdk (sign in, sign up).
The web application also implements the use of react native aws-amplify sdk pubsub to subscribe to an MQTT topic in IoT Core and retrieve messages but only to authenticated users.
As per step 2 in the pubsub documentation: Attach your policy to your Amazon Cognito Identity.
If I use the AWS CLI to attach the IoT policy to the user and then I sign in with that user through the web application I am able to successfully subscribe and receive MQTT messages -- it works perectly!
Problem:
The application allows Cognito self-service user sign up (Self-registration) and expects to have many users.
I implemented a post authentication lambda trigger function in the Cognito user pool created by the Amplify service.
The lambda function runs the following sample from AWS documentation with two (2) additional console logs:
exports.handler = (event, context, callback) => {
// Send post authentication data to Cloudwatch logs
console.log ("Authentication successful");
console.log ("Trigger function =", event.triggerSource);
console.log ("User pool = ", event.userPoolId);
console.log ("App client ID = ", event.callerContext.clientId);
console.log ("User ID = ", event.userName);
*** console.log("Event = ", event);
console.log("Context = ", context);***
// Return to Amazon Cognito
callback(null, event);
};
I then authenticate with the user again through the application and go to CloudWatch logs for that Lambda function.
This is the information I get from logging Event and Context after post authentication trigger:
Event log:
{
version: '1',
region: 'us-east-1',
userPoolId: 'us-east-1_*********',
userName: '4eea4a48-92b6-45da-b26e-*********',
callerContext: {
awsSdkVersion: 'aws-sdk-unknown-unknown',
clientId: '*********'
},
triggerSource: 'PostAuthentication_Authentication',
request: {
userAttributes: {
sub: '4eea4a48-92b6-45da-b26e-*********',
'cognito:email_alias': '*********.com',
'cognito:user_status': 'CONFIRMED',
email_verified: 'true',
name: 'asdfasdf',
email: '*********.com'
},
newDeviceUsed: false
},
response: {}
}
Context log:
{
callbackWaitsForEmptyEventLoop: [Getter/Setter],
succeed: [Function (anonymous)],
fail: [Function (anonymous)],
done: [Function (anonymous)],
functionVersion: '$LATEST',
functionName: 'userAccess_iotCore_attachPolicyToCognitoIdentityID',
memoryLimitInMB: '128',
logGroupName: '/aws/lambda/userAccess_iotCore_attachPolicyToCognitoIdentityID',
logStreamName: '2023/01/13/[$LATEST]4eb4287aa4db4dd8a6b6efd810a7***',
clientContext: undefined,
identity: undefined,
invokedFunctionArn: 'arn:aws:lambda:us-east-1:*********:function:userAccess_iotCore_attachPolicyToCognitoIdentityID',
awsRequestId: 'bf6afd1c-117c-4a9e-9d3b-*********',
getRemainingTimeInMillis: [Function: getRemainingTimeInMillis]
}
The big issue here is that context.identity is undefined so I am not able to get that authenticated user's Amazon Cognito Identity Id to attach the required IoT policy for PubSub to work through the application.
Questions:
How can I get the Amazon Cognito Identity Id after post authentication trigger to then attach an IoT policy?
From the web application using the aws-amplify sdk I am able to get this Id after sign in. Is there any API I can use from the application to attach this policy?
Thanks.
I have an API Gateway that i'm trying to add JWT authorization to. I have setup the authorization lambda based on this AWS resource. I have tested the lambda direct and also through the 'test' button and both generate the proper response policy document just fine.
But when i test through the endpoint with postman i always get 401
{
"message": "Unauthorized"
}
I turned on CloudWatch logging and also turned on X-Ray Tracing and the request is never logged at all. I see the logs for the test invocations and i see other logs for other non-authorized resources in CloudWatch and X-Ray.
If i disable the authorizer and deploy the request goes through just fine.
What gives?
Here is my authorizer code.
export async function handler(event) {
console.log(event);
let response = generatePolicy(null, 'Deny', event.methodArn);
let token = event.authorizationToken;
if (token) {
const jwt = await validateJwtSignature(token.substring(7)); // Strip "Bearer " from the begning of the token..
if (jwt) {
response = generatePolicy(jwt, 'Allow', event.methodArn);
}
}
console.log(JSON.stringify(response));
return response;
};
// Help function to generate an IAM policy
// Ex. generatePolicy('user', 'Deny', event.methodArn);
// Ex. generatePolicy('user', 'Allow', event.methodArn);
function generatePolicy(jwt, effect, resource) {
const authResponse = {
principalId: (jwt || {}).sub
};
if (effect && resource) {
authResponse.policyDocument = {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: effect,
Resource: resource
}
]
};
}
return authResponse;
}
Turns out the AWS guide that is was using is not clear on step # 16 here where it says to use authorizationToken as the Token source.
This is wrong. It should be Authorization as that is the right header. The guide made me think that the Token Source and the property passed to the lambda were the same thing.
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
This is a working authorizer. Rather annoying that neither CloudWatch nor x-ray logging indicated that the request was rejected for that reason.
I have an AWS Cognito user pool/identity pool set up to authorize a Lambda function behind API-gateway. My lambda is using the AWS SDK for Node. The login process works fine. In my function, I have an CognitoIdentityServiceProvider object that I'm using to call the getUser function. The Access Key I'm giving the function is coming from the lambda variable event.requestContext.identity.accessKey. However, the function call fails with the following error viewable through my Cloud Watch logs:
{
"message": "Invalid Access Token",
"code": "NotAuthorizedException",
"time": "2019-08-03T20:34:50.511Z",
"requestId": ...,
"statusCode": 400,
"retryable": false,
"retryDelay": 36.048605458111794
}
How is the token that is given to me in the authenticated request invalid? I'm not even sure how to debug this, or what problems I should be looking for.
An example of how I am trying to make the call in my lamdba handler:
var AWS = require('aws-sdk');
AWS.config.region = "us-west-2";
let poolData = {
UserPoolId: MY_POOL_ID,
ClientId: MY_CLIENT_ID
};
const cognito = new AWS.CognitoIdentityServiceProvider(poolData);
export async function myHandler(event, context, cb) {
var params = {
AccessToken: event.requestContext.identity.accessKey
};
cognito.getUser(params, (err, user) => {
if (err) {
console.log(JSON.stringify(err));
}
let response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true,
},
body: { ... }
};
return cb(null, response);
});
}
I can test this API call from a React UI using AWS Amplify or a CLI test that both produce the same results in the backend. So I don't think it's necessarily how the function is being invoked. This is the method I use for CLI testing that will log in a user to the User Pool and make an API request on their behalf:
npx aws-api-gateway-cli-test \
--username='my-test-user#domain.com' \
--password='password' \
--user-pool-id='us-west-2_000000000' \
--app-client-id='00000000000000000000000' \
--cognito-region='us-west-2' \
--identity-pool-id='us-west-2:000000000-0000-0000-0000-000000000000' \
--invoke-url='https://00000000000.execute-api.us-west-2.amazonaws.com/dev' \
--api-gateway-region='us-west-2' \
--path-template='/myHandler' \
--method='GET'
The Access Token that is being passed from the API invocation has the "ASIA" prefix instead of the "AKIA" prefix if that is relevant here. I'm not sure what other info to include about my User Pool or anything else, so if that's relevant to the solution, I would be happy to provide it.
The accessKey you are passing to the getUser API is not the accessToken that it expects. event.requestContext.identity.accessKey is the IAM user access key and not the accessToken generated by AWS Cognito when user sign in. You will need to pass the JWT Access Token returned by Cognito initiateAuth API. Consider adding the access token in Authorization header when making the request.
I'm trying to register a temporary quicksight user and generate an embed url to put in my React App. However, when calling the register user api I get a 403 error for the CORS preflight OPTIONS request:
Access to XMLHttpRequest at 'https://quicksight.ap-southeast-2.amazonaws.com/accounts//namespaces/default/users' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource."
I've also tried using us-east-1 as my region, but that also fails.
Users sign into my webapp with Cognito credentials. The identity pool has an associated IAM role, and I've attached a policy to that role giving access to register a new quicksight user and get the embed url. My webapp currently uses the aws-sdk library to assume the role through sts, and then make the subsequent quicksight calls.
The React app is hosted on Amplify
quicksightRegisterUser(data) {
var params = {
AwsAccountId: 'QQQ',
Email: 'XXX',
IdentityType: 'IAM' ,
Namespace: 'default',
UserRole: "READER",
IamArn: 'arn:aws:iam::YYY:role/ZZZ',
SessionName: 'XXX',
UserName:'XXX'
};
var quicksight = new QuickSight();
quicksight.registerUser(params, function (err, data1) {
if (err) {
console.log("err register user");
console.log(err);
} // an error occurred
else {
console.log("Register User1");
console.log(data1)
}
})
}
As #sideshowbarker mentioned, you can't call the Quicksight API from your webapp.
The solution I found was to set-up a Lambda to generate the Embedding URL, given the user's Cognito Username and password.
Full details of the solution, and a step-by-step tutorial, can be found here:
https://github.com/aws-samples/amazon-quicksight-embedding-sample
I've been pulling out my hair trying to set Appsync and Cognito in my React Native app.
I've tried the two following ways:
Amplify.configure(config);
OR
Amplify.configure({
Auth: {
region: config.aws_cognito_region, // REQUIRED - Amazon Cognito Region
userPoolId: config.aws_user_pools_id, // OPTIONAL - Amazon Cognito User Pool ID
userPoolWebClientId: config.aws_user_pools_web_client_id, // User Pool App Client ID
},
});
AND
const client = new AWSAppSyncClient({
url: appSyncConfig.graphqlEndpoint,
region: appSyncConfig.region,
auth: {
type: appSyncConfig.authType,
jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken(),
},
});
OR
const client = new AWSAppSyncClient({
url: appSyncConfig.graphqlEndpoint,
region: appSyncConfig.region,
auth: {
type: appSyncConfig.authType,
apiKey: appSyncConfig.apiKey,
},
});
I've also followed these two tutorials Tackling user auth, Building a notes app.
In both cases, I get the following error in GraphQL with no description:
Error: Network error: Response not successful: Received status code
This is while in Authorization Type is Amazon Cognito User Pool. I've also tried AWS Identity and Access Management (IAM), but that gives me a 403 error. Can someone point me in a direction where I can debug this further?
It might be caused a typo in the docs / article you've read. Trying replacing :
auth: {
type: appSyncConfig.authType,
apiKey: appSyncConfig.apiKey
}
with :
auth: {
type: appSyncConfig.authenticationType,
apiKey: appSyncConfig.apiKey
}
I have the following code and its working for me:
import Amplify, { Auth } from 'aws-amplify';
import API, { graphqlOperation } from '#aws-amplify/api'
window.LOG_LEVEL = 'DEBUG';
Amplify.configure({
Auth: {
"identityPoolId":'ap-southeast-1:xxxxxx',
"mandatorySignIn": false,
"region": "ap-southeast-1",
"userPoolId": "ap-southeast-1_xxxx",
"userPoolWebClientId": "xxxxxxx"
},
API:{
"aws_appsync_graphqlEndpoint": 'https://xxxx.ap-southeast-1.amazonaws.com/graphql',
"aws_appsync_region": 'ap-southwest-1',
"aws_appsync_authenticationType": 'AMAZON_COGNITO_USER_POOLS',
"aws_appsync_apiKey": 'null',
}
});