Cannot write required AWS Cognito attribute - amazon-web-services

I created a user pool in AWS's Cognito, specified given_name and family_name as required user attributes. I also added an app and checked the permissions :
If - using the Cognito Identidy SDK - I try to register a user and omit the attributes, I get: "Attributes did not conform to the schema: given_name: The attribute is required family_name: The attribute is required" which is expected.
If I include the attributes:
const firstNameAttribute = new CognitoUserAttribute({ Name: 'first_name', Value: firstName });
const lastNameAttribute = new CognitoUserAttribute({ Name: 'last_name', Value: lastName });
cognitoUserPool.signUp(username, password, [firstNameAttribute], [lastNameAttribute], callback);
The server returns
{
"__type":"NotAuthorizedException",
"message":"A client attempted to write unauthorized attribute"
}
How can I fix this and let users set their name during registration?

The app in which the users would try register sent the wrong field names :(

You have to check Write permission is allowed in app client.
Location:
Amazon Cognito > User Pools > {User Pool} > App Integration > App
Client > Attribute read and write permissions > Edit

Related

Google API user creation with service account

I'm trying to create a user using Googles Directory API and a service account. However I'm getting the error
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://admin.googleapis.com/admin/directory/v1/users?alt=json returned "Not Authorized to access this resource/api". Details: "Not Authorized to access this resource/api">
I've created a service account on the Google Console and allowed Domain wide delegation. It also says the Admin SDK API is enabled for my project. However I can't seem to create a user. The documentation is confusing me slightly. Here is my implementation
def create_googleuser(content, randpass):
''' This function creates a Google Apps account for a user passing webhook contents and password as arguments '''
# Get User info from Webhook and store them in variables
firstname = get_firstname(content)
secondname = get_secondname(content)
emailaddress = firstname + "." + secondname + "#example.com"
# Connect to google API
userscope = ['https://www.googleapis.com/auth/admin.directory.user']
service_account_credentials = ('serviceaccountcredentials.json')
credentials = service_account.Credentials.from_service_account_file(service_account_credentials, scopes=userscope)
userservice = googleapiclient.discovery.build('admin', 'directory_v1', credentials=credentials)
# Create a user dictionary with user details
userinfo = {"primaryEmail": emailaddress,"name":{"givenName":firstname,"familyName":secondname},"password":randpass}
print (emailaddress)
# Create user through googleAPI
userservice.users().insert(body = userinfo).execute()
I'm thinking that my implementation is wrong rather than the permissions as the serviceaccountcredentials.json should have the correct permissions. Any suggestions?
There are two possibilities for getting this error.
If the API method requires an impersonated user to be used.
If the impersonated user has not the relevant service enabled.
Solution for case 1:
Follow the documentation to impersonate a user account.
Solution for case 2:
In the Admin console, open user information and check that the user is not suspended.
Open the "Apps" panel and check that the relevant service is "On".
May be caused by a user not having a license which allows access to the service (Cloud Identity instead of Google Workspace), or a user being in an organizational unit which has the service disabled.
Also this link might be helpful.
Thanks for the input. You were both correct to a point. Basically there were two issues. The service account user needs to be delegated domain administrator privileges that require domain admin actions, domain wide delegation isn't enough. Also the domain scope needed to be broader in the Admin console and the scope definition within the code. There is github issue open which helped here:
https://github.com/googleapis/google-api-nodejs-client/issues/1884
My working code looks like this
def create_googleuser(content, randpass):
''' This function creates a Google Apps account for a user passing webhook contents and password as arguments '''
# Get User info from Webhook and store them in variables
username = get_username(content)
firstname = get_firstname(content)
secondname = get_secondname(content)
emailaddress = firstname + "." + secondname + "#example.com"
# Connect to google API
userscope = ['https://www.googleapis.com/auth/admin.directory.user', 'https://www.googleapis.com/auth/admin.directory.user.security']
service_account_credentials = ('serviceaccountcredentials.json')
credentials = service_account.Credentials.from_service_account_file(service_account_credentials, scopes=userscope)
delegated_credentials = credentials.with_subject('domain.admin#example.com')
userservice = googleapiclient.discovery.build('admin', 'directory_v1', credentials=delegated_credentials)
# Create a user dictionary with user details
userinfo = {"primaryEmail": emailaddress,"name":{"givenName":firstname,"familyName":secondname},"password":randpass}
# Create user through googleAPI
userservice.users().insert(body = userinfo).execute()

Why can't I get more attributes from google provider via cognito UserInfo endpoint?

I have configured google provider via cognito user pool and I am able to login through google and get user information. And I have added many attributes on the attribute mapping page as shown in below screenshot.
The endpoint I am using to get user info is https://docs.aws.amazon.com/cognito/latest/developerguide/userinfo-endpoint.html.
The response data for user info is always:
data: {
identities: '[{"userId":"xxxx","providerName":"Google","providerType":"Google","issuer":null,"primary":true,"dateCreated":1587772412295}]',
email_verified: 'true',
email: 'xxxx#gmail.com',
username: 'Google_1xxxx'
}
Regardless how I update the attribute mappings, I always see above response. Why can't I get additional attributes like picture, given_name, birthday etc. Do I need to set any permission on google side?
In app client setting, I have below configuration:
In authorized scope, I have set: email openid profile

Customize email verification page AWS Cognito

I am using Amazon Cognito for user authentication. After the user is registered verification email is sent to his email address. After clicking on the email link he is prompted with this in his browser.
How can I customize this page in order to insert a script that will trigger deep links within the mobile application, and also make the page look bit nicer?
You can do that using Cognito triggers.
You can configure a trigger template to define a message with a link to a page you control.
The assets will be stored at: amplify/backend/auth/<your-resource-name>CustomMessage/assets
The documentation has more details
Cognito allows you to configure your User Pool to send an email to
your users when they attempt to register an account. You can configure
this email to contain a link to Cognito’s Hosted UI where the user’s
account will be marked as confirmed.
This trigger template allows you to define an email message with a
link to a static S3 bucket that you control, where the user’s account
will be confirmed and they can then be redirected to a URL of your
choice (presumably your application). The URL will automatically
contain the username as a query string parameters.
Please note that this trigger template will create an S3 resource. The
files that populate the static site are available for edit in
amplify/backend/auth/CustomMessage/assets. They
consist of:
index.html
spinner.js (controls the spinner that appears on the page while users are awaiting confirmation)
style.css
verify.js (the script which performs the verification request)
I was not able to customize the verification page provided by AWS. I created my own UI on my page, which sent the generated code to cognito for verification. For that I needed to:
trigger custom email upon registration
put custom link to verification in the email using the codes provided for the lambda
process the codes on my page
send the codes and username through aws package
Step 1.
In AWS Cognito User Pool, customize workflow with triggers, choose "Custom Message". The triggerSource for verification that I check for are:
event.triggerSource === 'CustomMessage_SignUp' || event.triggerSource === 'CustomMessage_ResendCode'
You can see other trigger sources for CustomMessage here: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-message.html
Step 2. The lambda provides parameters for verification for my users: event.request.userAttributes.sub and event.request.codeParameter. Using these to I constructed a link to my page like so:
https://mypage.com?user_name=${event.request.userAttributes.sub}&confirmation_code=${event.request.codeParameter}
Step 3. On my page, I check if the url params for user_name and confirmation_code are present, and display a modal which is supposed to inform the user if the verification went correctly or not.
Using a package "amazon-cognito-identity-js" I process the code and user_name. First I create the user pool:
import { CognitoUserPool } from 'amazon-cognito-identity-js';
//Aws-cognito credentials
const poolData = {
UserPoolId: YOUR_USERPOOL_ID,
ClientId: YOUR_CLIENT_ID,
};
export default new CognitoUserPool(poolData);
Then to process the code I create a user instance:
import { CognitoUser } from 'amazon-cognito-identity-js';
import UserPool from 'utils/UserPool';
const getUser = () => {
return new CognitoUser({
Username: user_name.toLowerCase(),
Pool: UserPool,
});
};
// After that you can process the code:
getUser().confirmRegistration(code, false, function (err, result) {
if (err) {
if (
err.message === 'User cannot be confirmed. Current status is CONFIRMED'
) {
// Handle already confirmed error
} else {
// Handle other errors you want
}
}
// Handle successful verification
});
The account is verified and you can guide the user to the login page or any other.

Custom attributes missing in the getUserAttributes response - AWS cognito

const userData = { Username: username, Pool: userPool };
const cognitoUser = new AWS.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.getUserAttributes(function(err, result) {
if (err) {
alert(err);
return;
}
console.log(result)
for (i = 0; i < result.length; i++) {
console.log('attribute ' + result[i].getName() + ' has value ' + result[i].getValue());
}
});
I have a custom field userType. I have set the read, write permission for the custom attribute. But in the response of getUserAttributes i am getting only standard attributes(sub, email_verified, email). How can i retrieve both the standard and custom attributes?
This is my response
First of all, you need to make sure the App client has permissions to read the attribute(s).
Go to AWS Cognito, select the User Pool, then General Settings > App clients and select the App Client, then click "Set attribute read and write permissions"
You should see the following options (notice I have "custom:premium" attribute created and permission to read set)
Then in order to see the custom attributes in cognitoUser.getUserAttributes() results you need to set some value to it, this can be done for example via AWS CLI with the following command:
aws cognito-idp admin-update-user-attributes \
--user-pool-id userPoolId \
--username userName \
--user-attributes Name=custom:premium,Value=1
In the example above I'm setting "custom:premium" attribute to value 1 (obviously you need to replace userPoolId and userName with correct values.
userPoolId can be found in AWS Cognito (for example: eu-central-1_896ERRASw)
userName is username of the user you are currently logged in with in your app (and invoking cognitoUser.getUserAttributes())
And here is the result of the function call after properly setting permission and value of the custom attribute.
Hope it helps!

AWS Cognito NotAuthorizedException A client attempted to write unauthorized attribute

I'm using AWS Cognito and aws-cpp-sdk for my application. I defined a user pool and an application, then I got app client id and app secret.
I can create user pool object:
Aws::Client::ClientConfiguration clientConfig;
clientConfig.region =
Aws::Region::EU_CENTRAL_1; // "RegionEndpoint.EUCentral1";
clientConfig.scheme = Aws::Http::Scheme::HTTPS;
clientConfig.connectTimeoutMs = 30000;
clientConfig.requestTimeoutMs = 600000;
CognitoIdentityProviderClient client;
client = CognitoIdentityProviderClient(clientConfig);
DescribeUserPoolClientRequest describeUserPoolClientRequest;
describeUserPoolClientRequest.WithUserPoolId(POOL_ID)
.WithClientId(TEST_APP_CLIENT_ID);
DescribeUserPoolClientOutcome describeUserPoolClientOutcome =
client.DescribeUserPoolClient(describeUserPoolClientRequest);
After I defined an user with SignUpRequest, there was an error like this: NotAuthorizedException A client attempted to write unauthorized attribute
This is my signup code:
SignUpRequest signUpRequest;
signUpRequest.SetClientId(describeUserPoolClientOutcome.GetResult()
.GetUserPoolClient()
.GetClientId());
signUpRequest.SetUsername("xxxxx");
signUpRequest.SetPassword("xxxxxx?");
AttributeType email, phone_number, gender, given_name, family_name, picture;
email.WithName("email").WithValue("gacer#ku.edu.tr");
phone_number.WithName("phone_number").WithValue("+xxxxx");
given_name.WithName("given_name").WithValue("xxx");
family_name.WithName("familiy_name").WithValue("xxx");
gender.WithName("gender").WithValue("MALE");
picture.WithName("picture").WithValue(
"http://xxxx");
signUpRequest.AddUserAttributes(email);
signUpRequest.AddUserAttributes(phone_number);
signUpRequest.AddUserAttributes(given_name);
signUpRequest.AddUserAttributes(family_name);
signUpRequest.AddUserAttributes(gender);
signUpRequest.AddUserAttributes(picture);
SignUpOutcome signUpOutcome = client.SignUp(signUpRequest);
What is the problem? How can I solve it?
In the AWS website go to your User Pool -> Apps -> Show Details -> Set attribute read write permissions. Make sure every attribute you are trying to write i in the writeable attributes list and they have a checkmark.
I have same problem but it was resolved by adding custom: in other attributes.
While you are adding custom attributes
you need to add
custom:family_name
Omg! The reason of exception is only writing mistake. The problem is solved by correcting typing error from familiy to family at this line:
family_name.WithName("familiy_name").WithValue("xxx");