Authenticate AppSync queries console with Cognito User Pools - amazon-cognito

I am trying to authenticate Queries playground in AWS AppSync console. I have created User Pool and linked it to the AppSync API, I have also created an App Client in Cognito User Pool (deployed using CloudFormation). It appears under Select the authorization provider to use for running queries on this page: in the console.
When I run test query I get:
{
"errors": [
{
"errorType": "UnauthorizedException",
"message": "Unable to parse JWT token."
}
]
}
This is what I would expect. There is an option to Login with User Pools. The issue is I can't select any Client ID and when I choose to insert Client ID manually, anything I enter I get Invalid UserPoolId format. I am trying to copy Pool ID from User Pool General settings (format eu-west-2_xxxxxxxxx) but no joy. Btw, I am not using Amplify and I have not configured any Identity Pools.
EDIT:
Here is the CloudFormation GraphQLApi definition:
MyApi:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Sub "${AWS::StackName}-api"
AuthenticationType: AMAZON_COGNITO_USER_POOLS
UserPoolConfig:
UserPoolId: !Ref UserPoolClient
AwsRegion: !Sub ${AWS::Region}
DefaultAction: ALLOW

To set up the stack using CloudFormation I have followed these 2 examples:
https://adrianhall.github.io/cloud/2018/04/17/deploy-an-aws-appsync-graphql-api-with-cloudformation/
https://gist.github.com/adrianhall/f330a10451f05a529680f32978dddb64
Turns out they both (same author) have an issue in them in the section where ApiGraphQL is defined. This:
MyApi:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Sub "${AWS::StackName}-api"
AuthenticationType: AMAZON_COGNITO_USER_POOLS
UserPoolConfig:
UserPoolId: !Ref UserPoolClient
AwsRegion: !Sub ${AWS::Region}
DefaultAction: ALLOW
Should be:
MyApi:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Sub "${AWS::StackName}-api"
AuthenticationType: AMAZON_COGNITO_USER_POOLS
UserPoolConfig:
UserPoolId: !Ref UserPool
AwsRegion: !Sub ${AWS::Region}
DefaultAction: ALLOW
Thank you #Myz for pointing me back to review the whole CF yaml file

Related

Cognito Custom Auth trigger not getting Session from Cognito

I tried to call the InitiateAuth API from AWS CLI. I have set up Define auth, create auth and verify auth lambda triggers correctly. The problem is that, when I ran the below command, it's showing error:
aws cognito-idp initiate-auth --client-id <my_client_id> --auth-flow CUSTOM_AUTH --auth-parameters USERNAME=uname,ChallengeName="SRP_A",SRP_A="<srp_value>"
Error: An error occurred (UserLambdaValidationException) when calling the InitiateAuth operation: DefineAuthChallenge failed with error Cannot read property 'challengeName' of undefined.
I checked the Define Auth lambda code, and also the Cloud Watch logs of Lambda execution. The error occurred because the input from Cognito contains an empty session key in the event json (which usually sent from Cognito to Lambda). As the property challengeName resides inside the session key (as shown in official documentation).
Here is the JSON event sent to Lambda from Cognito when I ran that command (I got this JSON from CloudWatch Lambda logs, I printed the event which is being sent from Cognito):
{
version: '1',
region: 'us-east-1',
userPoolId: 'us-east-1_******',
userName: 'uname',
callerContext: {
awsSdkVersion: 'aws-sdk-unknown-unknown',
clientId: '<my_client_id>'
},
triggerSource: 'DefineAuthChallenge_Authentication',
request: {
userAttributes: {
sub: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx',
'cognito:email_alias': '<email>',
'cognito:user_status': 'CONFIRMED',
email_verified: 'true',
name: 'Custom Test',
email: '<email>'
},
session: [], -----> !! Empty
userNotFound: false
},
response: { challengeName: null, issueTokens: null, failAuthentication: null }
}
What is the reason? Is it because I am sending the request from CLI so Cognito not able to create a session or something? I'm not sure. Any help will be appreciated.
Session holds previous auth challenge results (either from built-in challenges or you custom challenges). It will be empty for the first invocation of the define auth challenge lambda. As the name suggests you have to define the auth challenge in the handler response.

AWS Amplify API authentication error for unauthenticated user

I created a books API with Amplify for an iOS app. I want the book table to have read access for both authenticated and unauthenticated users. Here's the schema:
type Book
#model
#searchable
#auth(
rules: [
{allow: private, provider: userPools, operations: [read]},
{allow: groups, groups: ["Admin"]}
]
)
{
id: ID!
category: BookCategoryType!
description: String
groupsCanAccess: [String]!
images: [Image!]
#auth(rules: [
{allow: groups, groupsField: "groupsCanAccess", operations: [read]},
{allow: groups, groups: ["Admin"]}
])
title: String!
}
However, when calling fetch from AWSAppSyncClient, I get the following error:
authenticationError(AWSMobileClient.AWSMobileClientError.notSignedIn(message: "User is not signed in, please sign in to use this API."))
The Cognito identity pool has Enable access to unauthenticated identities checked and there's an unauth IAM role.
What could be the problem?

Configure AWS Cognito User Pool Advanced Security Features Account Takeover Risk Configuration via CLI

Attempting to configure my Cognito user pool via the CLI
If I run
aws cognito-idp set-risk-configuration --user-pool-id ap-southeast-2_123456789 --account-takeover-risk-configuration Actions={LowAction={Notify=false,EventAction=NO_ACTION},MediumAction={Notify=false,EventAction=NO_ACTION},HighAction={Notify=false,EventAction=NO_ACTION}}
I just get the error
Unknown options: Actions=MediumAction=Notify=false, Actions=MediumAction=EventAction=NO_ACTION, Actions=HighAction=Notify=false, Actions=HighAction=EventAction=NO_ACTION, Actions=LowAction=EventAction=NO_ACTION
I have tried simplifying my request to just
aws cognito-idp set-risk-configuration --user-pool-id ap-southeast-2_123456789 --account-takeover-risk-configuration Actions={HighAction={EventAction=NO_ACTION}}
And I get the error
Missing required parameter in AccountTakeoverRiskConfiguration.Actions.HighAction: "Notify"
So I know I am on the right track, but then when I change my command to
aws cognito-idp set-risk-configuration --user-pool-id ap-southeast-2_123456789 --account-takeover-risk-configuration Actions={HighAction={EventAction=NO_ACTION,Notify=false}} to satisfy the missing param, I get Unknown options: Actions={HighAction=Notify=false}
What is the correct syntax for the Notify param?
Confirmed by AWS support as a bug where the boolean is simply being dropped by the parser
Only fix is to use an external JSON file for the props.
set-risk-configuration --user-pool-id ap-southeast-2_123456789 --account-takeover-risk-configuration file://riskconfig.json
riskconfig.json
{
"Actions": {
"LowAction": {
"Notify": false,
"EventAction": "NO_ACTION"
},
"MediumAction": {
"Notify": false,
"EventAction": "NO_ACTION"
},
"HighAction": {
"Notify": false,
"EventAction": "NO_ACTION"
}
}
}

How to connect to S3 bucket without providing Access and Secret keys in code with Keystonejs?

I have already tried using few keystonejs adapters : keystone-storage-adapter-s3 ,keystone-s3-upload-adapter.
But Access and Secret keys are required parameters in these adapters.
I want to connect to the bucket using IAM roles.
This is the code for adapter which doesn't allow access without Access and Secret keys or with IAM roles.
adapter: require('keystone-storage-adapter-s3'),
s3: {
key: 's3-key', // required; defaults to process.env.S3_KEY
secret: 'secret', // required; defaults to process.env.S3_SECRET
bucket: 'mybucket', // required; defaults to process.env.S3_BUCKET
path: '/profilepics',
headers: {
'x-amz-acl': 'public-read', // add default headers; see below for details
},

When I try to login using AWS Cognito I get an AccessDeniedException about my custom Lambda trigger

I am calling adminInitiateAuth and getting back a strange AccessDeniedException for my own lambdas.
Here is the code I'm calling:
var params = {
AuthFlow: "ADMIN_NO_SRP_AUTH",
ClientId: "#cognito_client_id#",
UserPoolId: "#cognito_pool_id#",
AuthParameters: {
USERNAME : username,
PASSWORD : tempPassword
},
};
cognitoIdentityServiceProvider.adminInitiateAuth(params, function(error, data) {
if (error) {
console.log("ERROR! Login failed: " + JSON.stringify(error), error.stack);
} else {
console.log("Login sent back: " + JSON.stringify(data));
}
});
The error message I'm getting is:
ERROR! Login failed: {"message":"arn:aws:lambda:us-east-1:201473124518:function:main-devryan-users_onCognitoLogin failed with error AccessDeniedException.","code":"UnexpectedLambdaException","time":"2017-02-25T18:54:15.109Z","requestId":"ce42833f-fb8b-11e6-929b-2f78b63faa12","statusCode":400,"retryable":false,"retryDelay":1.0853444458916783} UnexpectedLambdaException: arn:aws:lambda:us-east-1:201473124518:function:main-devryan-users_onCognitoLogin failed with error AccessDeniedException.
Does anybody know why I might be getting this error?
This was happening because I recreated my API Gateway & Lambdas (using serverless) and it turns out that the Cognito console sneakily adds permissions to contact a given Lambda function when added as a trigger through the console.
To fix this in your CloudFormation / serverless.yml file:
resources:
Resources:
OnCognitoSignupPermission:
Type: 'AWS::Lambda::Permission'
Properties:
Action: "lambda:InvokeFunction"
FunctionName:
Fn::GetAtt: [ "UsersUnderscoreonCognitoSignupLambdaFunction", "Arn"]
Principal: "cognito-idp.amazonaws.com"
SourceArn:
Fn::Join: [ "", [ "arn:aws:cognito-idp", ":", Ref: "AWS::Region", ":", Ref: "AWS::AccountId", ":", "userpool/", "#cognito_pool_id#" ] ]
To fix this in the AWS console:
Go to the Cognito Console
Choose your user pool
Go to "Triggers"
Remove your custom trigger (set it to None) and click "Save"
Now reset it back and click "Save" again
Here's an interesting Amazon forum post that led me down the right track.
I had a problem similar to yours except I was trying to configure the Lambda with my Cognito User Pool through CloudFormation.
In the link that Ryan had posted there was a code sample someone posted. Namely Cognito needed the proper permissions to invoke the lambda function.
MyLambdaInvocationPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt MyLambdaFunctionName.Arn
Principal: cognito-idp.amazonaws.com
SourceArn: !GetAtt MyCognitoUserPoolName.Arn
For someone ending up here, trying to add cognito triggers via terraform, all you need to do is to add an aws_lambda_permission resource:
resource "aws_lambda_permission" "allow_execution_from_user_pool" {
statement_id = "AllowExecutionFromUserPool"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.<lambda>.function_name
principal = "cognito-idp.amazonaws.com"
source_arn = aws_cognito_user_pool.<pool>.arn
}
Found in this great post: https://www.integralist.co.uk/posts/cognito/
you can add the permission from the lambda Role (create a policy for cognito and add to to the lamda role ) . this solve my problem when i stuck into it
while creation of cloudformation stack - I got error like
User:arn:aws::12345678:user/xyz is not authorized to perform:
cognito-idp:CreateUserPool on resource:*(Service:AWSCognitoIdentityProviderService;
Status Code: 400; Error Code: AccessDeniedException;Request ID: xxxxx)
workaround :
went on to the Stack which is in Rollback state -> checked events and could see , (creation-failed) some Roles I don't have access ,
So , I checked IAM policy assigned to me - I was not having the access.
I created a new policy and assigned to myself as an Inline Policy by Importing it from AWS.
aws-cognito-idp
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Cognito-IDP",
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction",
"cognito-idp:*"
],
"Resource": "*"
}
]
}
note: you can restrict the access on resource and cognito-idp user.
with this - I am successfully able to create and deploy cloudformation Stack for the module.