How to specify an existing cognito user pool in servreless.yml?

I am trying to write the lambda function for custom message used for cognito user pool. I have something like this in my serverless.yml

events:

  • cognitoUserPool:
    pool: my_pool
    trigger: CustomMessage

“my_pool” is the pool name of an existing cognito user pool. After deployment, a new pool named “my_pool” is created. I deleted the new “my_pool”, and hoping my old “my_pool” will be used.

When I try to deploy again, I got an error like this: "User pool us-west-2_xxxxxxx does not exist. " “us-west-2_xxxxxxx” is the pool id of the newly created “my_pool”, which I already deleted.

My question is how can I specify an existing user pool in serverless.yml? I don’t need serverless to create a new pool for me. Is there a way to specify the pool id or pool arn?

Thanks!

4 Likes

I have the same question.
I was hoping that overriding the AWS resource would help, but it didn’t work for me:

See section: “Override AWS CloudFormation Resource”

I am having the same problem, using serverless to manage my backend services on AWS.

I’ve divided my project into two stacks: one that defines all the lambdas, and another that defines only resources, such as DynamoDB tables, and User Pools.

I’m now stuck not knowing how to define my PreSignUp trigger in the service stack, so that it will reference a User Pool that’s already been created. I can always manually go into the User Pool console and select the correct lambda, but that just seems wrong…

I’ve tried using an ARN where pool is specified, but I get a validation error (no colons accepted for example):

- cognitoUserPool:
    pool: "arn:aws:cognito-idp:us-east-1:XXXX:userpool/us-east-1_XXXXX"
    trigger: PreSignUp

The above does not work, so I’d like to know how to do this correctly.

2 Likes

I am having the very same issue. I do not want to create the user pool again. Why can we not reference an already existing Arn for user pool?

Well looks like I’m in the same boat with everyone else on this thread. Has nobody figured out a way to deal with this? I also have an existing user pool created and would love to just define my serverless.yml file to point to this user pool, but I cannot figure out how to do this.

2 Likes

I found this in cloudformation docs, Im a newb so not really sure how this works, but I I think serverless uses cloudformation under the hood?

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html

I am also dividing my app into 2 stacks as @tcchau is doing and ended up doing it backwards. The Cloudformation stack that defines the Cognito user pool specifies the ARN for the lambda trigger rather than letting Serverless try to connect the trigger to the user pool. This works because Cloudformation and/or Cognito does not seem to care that the user pool trigger configuration references a lambda that might not exist. This is ugly but gets around having to manually connect the pool to the trigger

1 Like

Thanks guys, I appreciate the response.

I’m struggling with the same problem and don’t understand what your suggested solution to the problem is from what you’ve written above. This is what I have in serverless.yml:

  postConfirmation:
    handler: triggers/postConfirmation.handler
    events:
      - cognitoUserPool:
          pool: ${self:custom.stage}-my-user-pool
          trigger: PostConfirmation

And this results in the same problem that others have described above (creates a separate user pool with same name as my actual user pool). What value should I use for the pool to prevent a separate pool being created? I’d be super grateful for any help with this.

I have a separate CloudFormation template that defines my Cognito user pool. In it I define the post confirm trigger as part of the user pool resource like this:

LambdaConfig:
    PostConfirmation: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${put your lambda name that will be generated by serverless here}'

This works cause Cognito does not seem to care that the ARN of the lambda function is bogus when the user pool is created.

Then I let serverless define the lambda but don’t connect it to any event. Leave the events section blank. If you use cognitoUserPool at all serverless will create a new pool.

Then there is one last piece. You need to give Cognito permission to invoke the post confirm lambda. I put this in serverless.yml:

resources:
  Resources:
    PostConfirmTriggerInvokePermission:
      Type: AWS::Lambda::Permission
      DependsOn: ${logical name of lambda generated by serverless}
      Properties:
        Action: lambda:InvokeFunction
        Principal: cognito-idp.amazonaws.com
        SourceArn: ${put user pool ARN here}
        FunctionName: ${lambda name generated by serverless}

In your case the DependsOn value should be PostConfirmationLambdaFunction - check the serverless-state.json file for the name that serverless generated.

The lambda name should be something like ${whatever your service name is}-${stage}-postConfirmation

This is very hacky but it works. I precreate my user pool via CloudFormation once, then use serverless to manage the post confirmation trigger and connect the invoke permissions.

2 Likes

Thanks very much for your reply. For now I’m sticking with manually adding the post confirmation trigger via the console but I now have a much better understanding of your solution.

There is now a flag called existing that will use an existing user pool

"PreSignUp": {
  "layers": [{ "Ref": "NodeModulesLambdaLayer" }],
  "handler": "src/handlers/cognito/index.preSignUp",
  "events": [
    {
      "cognitoUserPool": {
        "pool": "${self:custom.userPoolName}",
        "trigger": "PreSignUp",
        "existing": true
      }
    }
  ]
},
1 Like

I was struggling with the same thing to protect part of the functionality of my lambda function. Maybe my situation is a bit different - but I did this. I hope it can give you some inspiration :wink:
So I use an existing user pool and force autorization on the API gateway.

I don’t know if this is the correct solution but it worked for me.
I created a new authorizer using the AWS console screen to use my existing Cognito User Pool and I set the Authorizer Id inside my serverless yam file, like this:

apimethod:
    handler: api/xxxx.handler
    description: GET /xxxxx
    events:
      - http:
          path: xxxxx
          method: get
          cors:
            origin: '*'
            headers: ${self:custom.allowedHeaders}
          authorizer: 
            type: COGNITO_USER_POOLS
            authorizerId: ${self:provider.authorizerID}```

That helped me a lot, thank you!

I cannot however find anywhere in documentation mention of PostConfirmTriggerInvokePermission. Could you tell me where in the docs do you find mention of this property?
Thanks again!

That is just the name I gave the resource in the Resources section of my serverless.yml. The Resources section has to be CloudFormation syntax. You can call it whatever you want. The important part was configuring the Lambda permission.

1 Like

Why can we not reference an already existing Arn for user pool?

Speed Test

This might help someone, especially for existing user pools:

  cognitoUserPool: {
    pool: "**POOL NAME (NOT ID, NOT ARN)**",
    trigger: "PreAuthentication",
    **existing: true,**
    // This flag (forceDeploy) has to be used in conjunction with the existing: true flag.
    // (https://www.serverless.com/framework/docs/providers/aws/events/cognito-user-pool#forcing-deploying-of-triggers)
    **forceDeploy: true**
  },

I know there is one option to import it Manually from AWS Console, and then referencing it in the serverless.yml using this manual - aws.amazon.com/blogs/aws/… .