AWS Cognito created by Serverless doesn't send confirmation emails - amazon-web-services

I'm working on an serverless authentication and I've got a problem with sending confirmation email.
When I create a user by AWS Console, the user is created and email with confirmation code is sent.
But when I do a request to API, user is created in Cognito but no email is sent.
What could be wrong with my code or request?
This is Cognito resource defined in serverless.yml:
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: ${self:service}-${self:provider.stage}-user-pool
UsernameAttributes:
- email
AutoVerifiedAttributes:
- email
EmailConfiguration:
EmailSendingAccount: COGNITO_DEFAULT
And it is request which I send to API:
POST / HTTP/1.1
Host: cognito-idp.eu-central-1.amazonaws.com
X-Amz-Target: AWSCognitoIdentityProviderService.SignUp
X-Amz-User-Agent: aws-amplify/0.1.x js amplify-authenticator
Content-Type: application/x-amz-json-1.1
Content-Length: ###
{
"ClientId": "####################",
"Username": "##########.##",
"Password": "####################",
"ValidationData": null
}

I resolved the problem by creating preSignUp lambda trigger with auto-confirming user:
const handler: PreSignUpTriggerHandler = async (event: PreSignUpTriggerEvent, context, callback) => {
event.response.autoConfirmUser = true;
callback(null, event);
};
Docs
AWS: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html
Serverless: https://www.serverless.com/framework/docs/providers/aws/events/cognito-user-pool/

I work with different framework (Amplify), but as the both frameworks use Cognito User pools, I guess the issue would be that you are missing "domain name".
In AWS Console, check your User Pool, then in (left panel) find "App integration" and then open and setup "Domain Name".
Again, I am just guessing (sorry, if my advice will not help), but I experienced similar problem.

Related

How can I attach an IoT Core policy to a Cognito Identity Id on a post authentication Lambda trigger for an Amplify deployed web application?

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 am not able to use authorization with cognito

I have configured my api to authorized against cognito user pool following is a example of the configuration.
getRecords:
handler: abc.def.GetRecords
events:
- http:
path: /getRecords
method: get
authorizer:
- {arn of coginito userPool}
When i pass access_token while calling the API i don't get response, but when i pass id_token it let me though with the authorisation, but i want it to work with access_token but not with id_token, Please help me to solve this usecase

Amazon Cognito: add custom parameters to authorize URL when using OIDC identity provider

As stated in the title, I would like to add a custom parameter to the /authorize URL to which Cognito redirects when working with a OIDC User Pool Identity Provider (in my case https://example.xx.auth0.com/authorize).
I found out you can specify an authorize URL through cloudformation but it cannot contain query parameters.
More details:
Cognito is configured through Serverless (which uses Cloudformation under the hood):
Auth0IdentityProvider:
Type: AWS::Cognito::UserPoolIdentityProvider
Properties:
UserPoolId:
Ref: CognitoUserPool
ProviderType: "OIDC"
ProviderName: "Auth0"
ProviderDetails:
client_id: "xxxx"
client_secret: "xxxx"
attributes_request_method: "GET"
oidc_issuer: "https://xxxx.xx.auth0.com"
authorize_scopes: "openid profile email"
AttributeMapping:
email: "email"
When navigating to the Cognito hosted UI and selecting the Auth0 provider it redirects to the /authorize Cognito endpoint which in turn redirects to the /authorize Auth0 endpoint.
I need to add the connection parameter to Auth0's /authorize in order to bypass its UI and go straight to the social login but I haven't been able to find a way to do so.
Turns out that when configuring your Auth0 client you can specify the connection parameter and Auth0 will skip its UI for you, but it will only do that if the configured redirect_uri does not point to localhost.
auth0 = await createAuth0Client({
redirect_uri: window.location.origin,
scope: "openid profile email offline_access",
connection: "linkedin",
});

API Gateway not returning Response

I was trying GCP API Gateway using firebase authentication. I can see my request has been processed from the logs and completed with response code 200. However, I am not getting the response back to my client. I am getting the response when I call the function directly. Am I missing something ?
API Config
swagger: "2.0"
info:
title: API Endpoints
description: API Endpoints
version: 1.0.1
schemes:
- https
produces:
- application/json
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://securetoken.google.com/my-project"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "my-project"
paths:
/hello:
get:
summary: Test link
operationId: hello
x-google-backend:
address: https://us-central1-my-project.cloudfunctions.net/hello
security:
- firebase: []
responses:
"200":
description: A successful response
schema:
type: string
"403":
description: Failed to authenticate
Function
* Responds to any HTTP request.
*
* #param {!express:Request} req HTTP request context.
* #param {!express:Response} res HTTP response context.
*/
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
Logs
Additional Query
Initially, I had my functions private and was getting 403. It gave me 200 once I added allUsers with Cloud Functions Invoker to the permissions to the function I am trying to invoke. So I am a bit confused here. Part of the reason I am using API gateway with firebase auth is to protect it against unauthorised calls. And for firebase auth to work, I had to add allUsers, making it public. My understanding was that the API gateway alone would be public while all the backend services that it invokes would be private. In this case, the function can be directly invoked by anyone, rendering API Gateway useless. How can I setup the backend to private and only respond to authenticated calls through API gateway ?
Additional Logs
{
insertId: "8c13b49c-2752-4216-8188-d445f4724ef14850908905639612439#a1"
jsonPayload: {
api_key_state: "NOT CHECKED"
api_method: "1.myapi.GenerateRTCToken"
api_name: "1.myapi"
api_version: "1.0.1"
client_ip: "999.999.999.999"
http_method: "GET"
http_response_code: 200
location: "us-central1"
log_message: "1.myapi.GenerateRTCToken is called"
producer_project_id: "myproject"
request_latency_in_ms: 161
request_size_in_bytes: 4020
response_size_in_bytes: 579
service_agent: "ESPv2/2.17.0"
service_config_id: "myapi-config"
timestamp: 1606313914.9804168
url: "/generateRTCToken"
}
logName: "projects/myproject/logs/myapi%2Fendpoints_log"
receiveTimestamp: "2020-11-25T14:18:36.521292489Z"
resource: {
labels: {
location: "us-central1"
method: "1.myapi.GenerateRTCToken"
project_id: "myproject"
service: "myapi"
version: "1.0.1"
}
type: "api"
}
severity: "INFO"
timestamp: "2020-11-25T14:18:34.980416865Z"
}
To call the Google Cloud Function from the Api-Gateway without making it public you can grant the service account used by the API-Gateway the role CloudFunctions Invoker
On Creating an API config (4) : you set a service Account, take note of this service account.
Once you have identified the service account you can grant it the Cloud Funtions Invoker role to the service account. For these you can follow these steps:
Go to IAM&Admin
Look for the service account, and click on the pencil next to it( If you don't see the service account click on Add and type the service account email)
For role Select Cloud Functions Invoker
Click on Save
This will grant the service account the permission to call the functions without having them public.
I have an similar issue with API Gateway throwing the same response validating a token against keycloak.
The issue was with the JWT, it was too long, we remove unused roles from the user and work perfectly.
Hope it helps.
Take a look at this document where it is explained in detail how to use Firebase to authenticate in API Gateway.
In general there are two conditions that we need to keep on mind in order to configure these services:
When your client application sends an HTTP request, the authorization header in the request must contain the following JWT claims:
iss (issuer)
sub (subject)
aud (audience)
iat (issued at)
exp (expiration time)
To support Firebase authentication, add the following to the security definition in your API config:
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
# Replace YOUR-PROJECT-ID with your project ID
x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "YOUR-PROJECT-ID"

aws-sdk 403 Error for CORS preflight OPTIONS request to Quicksight API

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