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?
Related
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
When I query GitHub's GraphQL API with the following:
query RetrievePackagesAssociatedWithRepo($repo: String!, $owner: String!) {
repository(name: $repo, owner: $owner) {
packages(packageType: NPM, first: 10) {
edges {
node {
id
name
packageType
}
}
}
}
}
I received an error stating:
{
"errors": [
{
"type": "INSUFFICIENT_SCOPES",
"locations": [
{
"line": 6,
"column": 11
}
],
"message": "Your token has not been granted the required scopes to execute this query. The 'id' field requires one of the following scopes: ['read:packages'], but your token has only been granted the: ['read:gpg_key', 'read:org', 'read:public_key', 'read:repo_hook', 'repo', 'user'] scopes. Please modify your token's scopes at: https://github.com/settings/tokens."
},
I followed the link https://github.com/settings/tokens and added the necessary permissions.
I tried to Authorizing a personal access token for use with SAML single sign-on but, the SSO button to enable is not present.
development settings token
Documentations I Followed: Creating Personal Token! | Authorizing Personal Token!
After trying out theses methods, the same error message persists "Your token has not been granted the required scopes".
My goal, through Github's API, is to retrieve packages associated with its repository.
Is there something I'm missing.
I have the following security schemes defined for a method in my swagger file:
...
get:
...
security:
- api_key: []
- firebase: []
securityDefinitions:
api_key:
in: query
name: key
type: apiKey
firebase:
authorizationUrl: ''
flow: implicit
type: oauth2
x-google-audiences: project-id
x-google-issuer: https://securetoken.google.com/project-id
x-google-jwks_uri: https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com
However, it will not work if I try to send a request using an api key, but it will if I use a firebase token (even if I do not provide the api key).
The response:
{
"code": 16,
"message": "JWT validation failed: Missing or invalid credentials",
"details": [
{
"#type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "auth"
}
]
}
If I remove firebase from the security definition, then it will work using the api key.
Is it a known issue that an api key security scheme will not work if there is also an oauth2 for the same method?
What happens is that "OR" security requirements are not supported when one of the alternatives is an API key. Therefore, you are experiencing the right behavior.
If you provide both alternatives the API key will be ignored, but if OAuth2 is removed and it only accepts the API key, it works.
According to the same documentation that I attached, you could require both authentication methods using an "AND" condition. Something like this:
...
security:
- api_key: []
firebase: []
....
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.
I would like my app to allow users with a Facebook, Google, Amazon... etc... accounts to be able to login to my app. This works fine through AWS Cognito.
However, is there a way for the app to create a user login programmatically if the user does not have any of those logins?
The user would provide an id and a password and the app would send the information to the authentiation provider to create a new login/account.
I would not need to implement my own authentication mechanism and worry about how the passwords are stored, etc.
From my research I take that there is no way to do this with existing authentication providers or even other services such as OpenID.
Do you have any other options if I do not want to implement my own login storage and authentication? It would not necessarily need to integrate with AWS Cognito.
I'm a little confused by your question. If you're asking:
Can I create new usernames and passwords on Facebook / Google programatically?
Then the answer is no. You have to sign up for Facebook / Google on their site. If you're asking:
Can I create a new user with a username and password that only exists in Cognito?
Then the answer is yes. To do this, it depends on whether you're creating the user in a browser or on a server. In a browser, use the Cognito Javascript API. On a server, use the Cognito Admin Server APIs.
Here's some sample code for creating a new user on the server in Node JS (replace my strings with your own tokens, especially the ones with # signs in them):
let params = {
UserPoolId: "#cognito_pool_id#",
Username: "jhancock",
DesiredDeliveryMediums: ["EMAIL"],
ForceAliasCreation: false,
MessageAction: "SUPPRESS",
TemporaryPassword: "somePassword",
UserAttributes: [
{ Name: "given_name", Value: "John"},
{ Name: "family_name", Value: "Hancock"},
{ Name: "name", Value: "John Hancock"},
{ Name: "email", Value: "john#gmail.com"},
{ Name: "phone_number", Value: "+15125551212"}
],
};
console.log("Sending params to cognito: " + JSON.stringify(params));
let cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider({region: "us-east-1"});
cognitoIdentityServiceProvider.adminCreateUser(params, function(error, data) {
if (error) {
console.log("Error adding user to cognito: " + JSON.stringify(error), error.stack);
} else {
console.log("Received back from cognito: " + JSON.stringify(data));
}
}
One you get that working, you'll probably want to see this post about how to change the temporary password into a real one.
Hi from my previous experence in implementing of the social media authentication.
I would conclude that it is quite hard to implement.If you do not what to show web view to authenticate user in iOS you need to use iOS ACAccountStore class for this, but even this only gives opportunity to log in not to sign in.