Note: If your question is regarding the AWS Amplify Console service, please log it in the
official AWS Amplify Console forum
* Which Category is your question related to? *
Amplify Auth
* What AWS Services are you utilizing? *
Cognito
* Provide additional details e.g. code snippets *
Is there a way to create custom attributes in cognito during
amplify auth add
or by editing parameters.json
@achutkiran Are you referring to the social provider custom attributes?
User pool custom attributes like customer type
+1
You can manually change the cognito-cloudformation-template.yml
file after adding the authentication (but before running amplify push
.
AWS properties Cognito UserPool
_Snippet cognito-cloudformation-template.yml_
....
# BEGIN USER POOL RESOURCES
UserPool:
# Created upon user selection
# Depends on SNS Role for Arn if MFA is enabled
Type: AWS::Cognito::UserPool
UpdateReplacePolicy: Retain
Properties:
UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]]
Schema:
- Name: myCustomAttribute
Required: true
Mutable: true
AttributeDataType: String
- Name: myOtherCustomAttribute
Required: false
Mutable: true
AttributeDataType: String
AutoVerifiedAttributes: !Ref autoVerifiedAttributes
Policies:
PasswordPolicy:
MinimumLength: !Ref passwordPolicyMinLength
RequireLowercase: true
RequireNumbers: true
RequireSymbols: true
RequireUppercase: true
MfaConfiguration: !Ref mfaConfiguration
SmsVerificationMessage: !Ref smsVerificationMessage
SmsConfiguration:
SnsCallerArn: !GetAtt SNSRole.Arn
ExternalId: !Ref roleExternalId
...
When you add new environments this template will be used for creating the new user pools too.
Presently I am editing cloudFormationTemplate and parameters.json to add custom Attributes and groups. But problem is for any reason whenever i update auth i have to update template manually. So it will be better if custom Attributes are included in amplify cli.
@achutkiran You're right, we don't have in-built support for custom attributes yet and what you're trying out is currently the best way to go about it, but I'll tag this as a feture request and prioritize work on this.
@timkuilman @achutkiran Yes I figured that out. I prefer editing the CF templates as well. Been a while since I've been in there. But not too hard to follow. And it would be impossible to have all the AWS service options in the cli anyways. Thanks.
Thanks
I tried https://github.com/aws-amplify/amplify-cli/issues/1204#issuecomment-482028480 and update auth, but an update error occured.
cloudformation.yml
- Name: custom:store_name
Required: true
Mutable: true
AttributeDataType: String
parameter.json
"requiredAttributes": [
"...",
"custom:store_name"
],
Am I wrong in specifying?
@yukitaka13-1110 required attributes in Cognito must be defined in Cloudformation templates when you first create the user pool. Cognito does not allow this update. Here is a forum thread on the topic: https://forums.aws.amazon.com/thread.jspa?messageID=898280󛓨
@RossWilliams I tried https://github.com/aws-amplify/amplify-cli/issues/1204#issuecomment-482028480.
In this case, dose the myCustomAttribute
stands for custom attribute(ex user_type) ?
about https://github.com/aws-amplify/amplify-cli/issues/1761#issuecomment-507007122
I want to add custom attributes like user_type instead of required attribute.
Is it possible to add custom attributes by adding custom attributes in the cloudformation template and 'amplify push'?
@yukitaka13-1110 An example https://github.com/aws-amplify/amplify-cli/pull/1289/commits/83476b944852ffa000875074e200b4fd5ec6f88c?short_path=ac1bfc4#diff-ac1bfc471563fa82f8882dccfe0ec1c2.
My template looks like this:
Schema:
-
AttributeDataType: "String"
Mutable: true
Name: roles
StringAttributeConstraints:
MaxLength: 256
MinLength: 1
And it adds the custom attribute just fine.
@yukitaka13-1110 the important part of https://github.com/aws-amplify/amplify-cli/issues/1204#issuecomment-482028480 is that you must modify the cloudformation template before running amplify push. If you have an existing user pool, then you have already run push and it is too late to change Cognito without creating a new user pool.
myCustomAttribute is the name of the attribute.
Required fields cannot be added after you create a user pool. Optional fields are ok to add inside the Cognito console, but not in Cloudformation template. If you use the Cognito console you can set these optional attributes without creating a new user pool. Additionally, you can write a Custom Resource and use the AWS SDK to add non-required custom properties if you don't want to use the console.
The Cloudformation documentation here says that modifying the Schema field requires a replacement of the user pool, meaning it will not update an existing pool.
@RossWilliams Oh, I see. I'll try it
Thank you for answering in detail !
@RossWilliams I could do it.
Thank you so much !
Just FYI for anyone else attempting this, but the example shown in https://github.com/aws-amplify/amplify-cli/issues/1204#issuecomment-482028480 doesn't work exactly because custom attributes cannot be Required
Reason: Required custom attributes are not supported currently. (Service: AWSCognitoIdentityProviderService; Status Code: 400; Error Code: InvalidParameterException;
Therefore, you must omit the Required
property.
I would happy to be proven wrong if anyone has a way to get Required
custom attributes working?
@kaustavghosh06 any progress on this? Would be much cleaner to simply add custom attributes through the amplify cli. Right now if I want to add a custom attribute in multiple environments, I need to do so manually on each cognito user pool. This can lead to errors.
@thedgbrt If you want to automate adding custom attributes today you can do this by creating a Custom Resource and use the aws-sdk to make the right API calls. A side benefit of using the API instead of cloudformation is that updates do not cause your user pool to be replaced.
You would need to use the amplify cli to add a new function, and allow it access to the auth category. Then you will have an environment variable "AUTH_COGNITO${project_name}_USERPOOLID" available in your lambda.
To have your Lambda run when you run amplify push, modify the function's Cloudformation template to add the custom resource inside the "Resources" object:
"CognitoAddCustomAttribute": {
"Type": "Custom::AddCustomAttribute",
"Properties": {
"ServiceToken": {
"Fn::GetAtt": [
"LambdaFunction",
"Arn"
]
},
"TriggerVersion": 1
}
},
your Lambda would have in its main body (for a numeric attribute):
const aws = require("aws-sdk");
const identity = new aws.CognitoIdentityServiceProvider({
apiVersion: "2016-04-18",
region: process.env.REGION
});
await identity
.addCustomAttributes({
UserPoolId: process.env.USERPOOL,
CustomAttributes: [
{
Name: "myCustomAttribute",
AttributeDataType: "Number",
Mutable: true,
Required:false ,
NumberAttributeConstraints: {
MinValue: "0",
MaxValue: "1000"
}
}
]
})
.promise()
Note that "myCustomAttribute" will be accessible as "custom:myCustomAttribute" for users, Cognito appends the "custom:" part for you.
The template property "TriggerVersion" can be incremented any time you need your function to be re-run in an environment.
I would also modify the "AmplifyResourcesPolicy" to only allow the specific actions you need to add a custom resource.
@RossWilliams thank you for taking the time to explain, made me realize amplify was much more powerful than I thought 馃憤
@RossWilliams I鈥檓 trying to take the custom resource approach you outlined, but my CF stack seems to hang during amplify push
. The function is run successfully and I see the custom attribute added to my user pool, but the amplify operation never completed (at least not before I cancel ~30 mins in). I think the custom resource may need to leverage cfn-response
? I tried with no success. Any tips?
@adamelmore, yes, look at 'cfn-response' or 'safe-cfn-custom-resource' to make sure you return a proper response for cloudformation, otherwise your stack with be stuck in an updating state until it times out. Sorry I didn't mention that cloudformation needs a specific response object from your lamba.
I had the same problem as @adamelmore and I solve this by using cfn-custom-resource package.
exports.handler = async function (event, context) { //eslint-disable-line
const cfnCR = require('cfn-custom-resource');
const { configure, sendSuccess, sendFailure, /*sendResponse,*/ LOG_VERBOSE, /*SUCCESS*/ } = cfnCR;
...
// For Delete requests, immediately send a SUCCESS response.
if (event.RequestType === "Delete") {
/* Resource successfully created! - async/await */
const result = await sendSuccess(physicalResourceId, {}, event);
return result;
}
....
/* Resource successfully created! - async/await */
const result = await sendSuccess(physicalResourceId, {}, event);
or
await sendFailure(err, event); // if it fails
@SanvirDessai I think this is about the sign-up request use a custom attribute set up in advance on the Cognito pool and doesn't automatically create such custom attribute. When I tested, I got a "Attributes did not conform to the schema: custom:X: Attribute does not exist in the schema."
I'm wondering if I miss something. Did you tested/got this working?
@rfpedrosa you are correct, you cannot create a custom attribute that is not part of the Cognito Attributes config. This is a low priority issue for us b/c it's mostly plug-and-play when adding new attributes.
It would be cool if Amplify could detect the custom attributes provisioned for a Cognito user pool -- which would be trivial if the CLI supported adding custom attributes! -- and plug those into an Amplify-generated migration trigger lambda, so existing attributes are copied over without needing to override the generated migration lambda.
I think it's kind of ridiculous that you can't create a custom Attribute via the CLI after the cognito pool is created and pushed. So basically if you miss something or down the road want to add something in anyway whatsoever you have to completely remake the pool? Especially since this has been alive for a year.
@JNeim
So basically if you miss something or down the road want to add something in anyway whatsoever you have to completely remake the pool? Especially since this has been alive for a year.
No, you can still add custom attributes using the AWS-cli per above comments. You do not need to replace the pool.
Isn't creating a Profile
model in the GraphQL a better approach to add custom fields?
There is another problem here, when using custom attribute, you can only set MaxLength, but on the cognito console, the unit is byte, it is maxByte in the console, and it is 2048, but MaxLength in cloudformation only 256 or something.
Here's a shell script to create custom attributes using AWS CLI:
#!/bin/sh
aws cognito-idp add-custom-attributes \
--user-pool-id <value> \
--custom-attributes \
'[
{
"Name": "string",
"AttributeDataType": "String"|"Number"|"DateTime"|"Boolean",
"DeveloperOnlyAttribute": true|false,
"Mutable": true|false,
"Required": true|false,
"NumberAttributeConstraints": {
"MinValue": "string",
"MaxValue": "string"
},
"StringAttributeConstraints": {
"MinLength": "string",
"MaxLength": "string"
}
}
...
]`
I couldn't get the custom resource method right, but this worked for me.
Most helpful comment
@thedgbrt If you want to automate adding custom attributes today you can do this by creating a Custom Resource and use the aws-sdk to make the right API calls. A side benefit of using the API instead of cloudformation is that updates do not cause your user pool to be replaced.
You would need to use the amplify cli to add a new function, and allow it access to the auth category. Then you will have an environment variable "AUTH_COGNITO${project_name}_USERPOOLID" available in your lambda.
To have your Lambda run when you run amplify push, modify the function's Cloudformation template to add the custom resource inside the "Resources" object:
your Lambda would have in its main body (for a numeric attribute):
Note that "myCustomAttribute" will be accessible as "custom:myCustomAttribute" for users, Cognito appends the "custom:" part for you.
The template property "TriggerVersion" can be incremented any time you need your function to be re-run in an environment.
I would also modify the "AmplifyResourcesPolicy" to only allow the specific actions you need to add a custom resource.