Cloudformation Cognito - how to setup App Client Settings, Domain, and Federated Identities via SAM template
Asked Answered
L

8

29

I already have my cognito user pool cloudformation template working, and have it integrated to my api gateway. But somehow i still have to manually configure the app client settings, domain, and federated identities to have a working login portal for the users. I have been looking here and there for possible solutions in automating these, but i cannot seem to find anything close to it.

I would like to automate the configuration of the app client settings, domain, and federated identities via cloudformation sam template so i do not have to do these manually.

Any suggestions are much appreciated. Thank you.

(attachments posted for additional info)

Lizbeth answered 28/3, 2018 at 0:57 Comment(2)
thanks in advance to all for any suggestions or answersLizbeth
According to my answer - what tool you using for automate? (like CodeBuild/Pipeline, Jenkins etc)Erosive
H
33

Update: Since end of 2019, AWS Cloudformation natively supports App Client Settings, Domain and Federated Identities. See other answers.

Looks like there is no way to provide App integration -> Domain name and Federation -> Identity providers via CloudFormation.

I found only reference for User Pool Client (General settings -> App clients) but it will not configure App integration -> App client settings.

If you need to automate process of providing Domain name, Identity providers and App client settings for user pool, you can do that by creating custom script (AWS CLI) or Lambda (AWS SDK) which should be performed after stack deployment.


**UPDATE**

Check out excellent example (answer below) that shows usage of CloudFormation Custom Resources with Lambda.

Handal answered 10/4, 2018 at 8:57 Comment(2)
thanks Michal, so far this is the best and honest answer i got. i agree, there maybe no way to do this via SAM template, but a custom script will. i was just hoping there was some way to automate it (as i am lazy). thanks man.Lizbeth
as of 3 October 2019, user pool domains are doable natively through cloudformation. See @matsev's answer below or this release page docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…Mithridatism
C
42

I have created two CloudFormation custom resources to apply Cognito app client settings and domain name. With these resources, you can have a script like this:

UserPoolTestClient:
  Type: 'AWS::Cognito::UserPoolClient'
  Properties:
    ClientName: UserPoolTestClient
    GenerateSecret: true
    UserPoolId: !Ref UserPoolTest
UserPoolTestClientSettings:
  Type: 'Custom::CognitoUserPoolClientSettings'
  Properties:
    ServiceToken: !GetAtt CloudFormationCognitoUserPoolClientSettings.Arn
    UserPoolId: !Ref UserPoolTest
    UserPoolClientId: !Ref UserPoolTestClient
    SupportedIdentityProviders:
      - COGNITO
    CallbackURL: 'https://www.amazon.com'
    LogoutURL: 'https://www.google.com'
    AllowedOAuthFlowsUserPoolClient: true
    AllowedOAuthFlows:
      - code
    AllowedOAuthScopes:
      - openid
UserPoolTestDomain:
  Type: 'Custom::CognitoUserPoolDomain'
  Properties:
    ServiceToken: !GetAtt CloudFormationCognitoUserPoolDomain.Arn
    UserPoolId: !Ref UserPoolTest
    Domain: 'userpool-test-01'

The complete code is here.

Calder answered 22/6, 2018 at 3:18 Comment(4)
Hi Rosberg, thanks for your response! I will check with my deployment and talk to our admin if we can still do changes (as we already have submitted the deployment). But thanks really. Where was this answer back then when i needed it most.Lizbeth
@rosberg-linhares: I see that you have specified openid in AllowedOAuthScopes. Does that imply that an OpenIDConnectProvider will be created behind the scenes? I have previously created another custom resource with an explicit call to iam.createOpenIDConnectProvider() but I am hoping to refactor that code.Carlcarla
@rosberg-linhares - This is great, thanks so much for starting this project. There is now a PR for creating IdentityProviders as well.Marabelle
There are also a couple of other (generic) options, namely: github.com/ab77/cfn-generic-custom-resource#cognito-demo and github.com/emdgroup/… (that I could find).Related
H
33

Update: Since end of 2019, AWS Cloudformation natively supports App Client Settings, Domain and Federated Identities. See other answers.

Looks like there is no way to provide App integration -> Domain name and Federation -> Identity providers via CloudFormation.

I found only reference for User Pool Client (General settings -> App clients) but it will not configure App integration -> App client settings.

If you need to automate process of providing Domain name, Identity providers and App client settings for user pool, you can do that by creating custom script (AWS CLI) or Lambda (AWS SDK) which should be performed after stack deployment.


**UPDATE**

Check out excellent example (answer below) that shows usage of CloudFormation Custom Resources with Lambda.

Handal answered 10/4, 2018 at 8:57 Comment(2)
thanks Michal, so far this is the best and honest answer i got. i agree, there maybe no way to do this via SAM template, but a custom script will. i was just hoping there was some way to automate it (as i am lazy). thanks man.Lizbeth
as of 3 October 2019, user pool domains are doable natively through cloudformation. See @matsev's answer below or this release page docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…Mithridatism
C
10

CloudFormation has added the resource AWS::Cognito::UserPoolDomain to manage the User Pool Domain:

Type: AWS::Cognito::UserPoolDomain
Properties: 
  CustomDomainConfig: 
     CertificateArn: !Ref CertificateArn
  Domain: "your.custom.domain.com"
  UserPoolId: !Ref UserPool

In addition, there has been added configuration to the AWS::Cognito::UserPoolClient:

Type: AWS::Cognito::UserPoolClient
Properties: 
  AllowedOAuthFlows: 
    - String
  AllowedOAuthFlowsUserPoolClient: Boolean
  AllowedOAuthScopes: 
    - String
  AnalyticsConfiguration: 
    AnalyticsConfiguration
  CallbackURLs: 
    - String
  ClientName: String
  DefaultRedirectURI: String
  ExplicitAuthFlows: 
    - String
  GenerateSecret: Boolean
  LogoutURLs: 
    - String
  ReadAttributes: 
    - String
  RefreshTokenValidity: Integer
  SupportedIdentityProviders: 
    - String
  UserPoolId: String
  WriteAttributes: 
    - String
Carlcarla answered 8/10, 2019 at 11:33 Comment(0)
L
5

Since yesterday, AWS CloudFormation added native support for configuring domain name, identities and other settings directly: https://aws.amazon.com/about-aws/whats-new/2019/10/amazon-cognito-increases-cloudformation-support/

This new support includes the ability to securely and automatically configure a hosted UI domain, configure customization for a hosted UI, configure an IdentityProvider, configure the behavior of advanced security features and configure resource servers, all directly within CloudFormation.

(thanks to my colleague Bernhard for this update)

Lucinalucinda answered 8/10, 2019 at 8:59 Comment(0)
P
2

I want to add a different solution (suggested by Mickael) because CloudFormation is complex to set up ; this command line will create your domain after the CloudFormation stack is created :

 aws cognito-idp create-user-pool-domain --domain test-domain --user-pool-id eu-west-1_xxxxxxxx 

In your automated deployment you can add a script that sets your domain. Not as great as everything on CF but it works

Playground answered 22/11, 2018 at 7:51 Comment(2)
custom resources worked great on my part. i cant use CLI as i need to have everything via SAM template.Lizbeth
Hi @jeff, can you provide the custom resource for the domain since the above mentioned Repo from Rosberg throws an error on that part?Broddie
G
2

I rolled a solution for these exact 3 resources for myself, and others that want to give it a shot. https://github.com/cyrfer/cloudformation-custom-resource-provider

Giagiacamo answered 9/7, 2019 at 6:10 Comment(0)
M
2

Very much inspired by Rosberg Linhares example, but in python, and using the AWS cfn helper module:

If you write a lambda function with this code, basically using boto3 to do the client app settings

from crhelper import CfnResource
import boto3
from copy import copy

# setup the cfn helper 
helper = CfnResource()
client = boto3.client('cognito-idp')

# these wrappers return the function unaltered, so we can chain them to apply
# the function in both create and update
@helper.create
@helper.update
def update_on_create(event, _):

        params = copy(event['ResourceProperties'])
        del params['ServiceToken']

        client.update_user_pool_client(**params) 

# don't do anything on delete. Deleting the client app is handled by the template
@helper.delete
def delete_user_pool_client(event, _):
        pass


def handler(event, context):
    helper(event, context)

Then your cloudformation would be similar, e.g.

UserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      ClientName: 'TestClient'
      GenerateSecret: true
      UserPoolId: !Ref UserPool
  UserPoolClientSettings:
    Type: Custom::CognitoUserPoolClientSettings
    DependsOn: 
        - LambdaForAppClientSettings
        - UserPoolClient
    Properties:
      ServiceToken: !GetAtt LambdaForAppClientSettings.Arn
      UserPoolId: !Ref UserPool
      ClientId: !Ref UserPoolClient
      CallbackURLs: 
          - https://www.amazon.com
      SupportedIdentityProviders:
          - COGNITO 

With the possible benefit that you can specify either some or all of the arguments to update_user_pool_client(), due to the parameter expansion in client.update_user_pool_client(**params). You do have to make sure that the keys in the Properties map of your cloudformation custom resource match exactly what is required by boto3. Check the boto3 documentation for the list of possible args.

Mithridatism answered 24/9, 2019 at 16:55 Comment(0)
A
2

As noted by matsev and Gregor, this can now be done easily via cloudformation. Meaning the accepted answer and the answer linked to the accepted answer are deprecated in the meantime.

See the documentation:

  1. UserPoolIdentityProvider
  2. UserPoolClient
  3. UserPoolDomain

Here is an example from my own template:

  UserPoolClient:
    Type: "AWS::Cognito::UserPoolClient"
    Properties:
      ClientName: !Sub ${AppName}-${Env}-appsync-client
      GenerateSecret: false
      UserPoolId: !Ref UserPool
      SupportedIdentityProviders:
        - COGNITO
        - Facebook
        #- SignInWithApple
        - Google
      AllowedOAuthFlowsUserPoolClient: true
      AllowedOAuthFlows: 
        - code
      AllowedOAuthScopes:
        - email
        - openid
        - profile
        - aws.cognito.signin.user.admin 
      CallbackURLs: 
        - !Sub ${AppName}://
      DefaultRedirectURI: !Sub ${AppName}://
      LogoutURLs: 
        - !Sub ${AppName}://
    DependsOn: 
      - GoogleCognitoUserPoolIdentityProvider
      #- AppleUserPoolIdentityProvider
      - FacebookCognitoUserPoolIdentityProvider

  CognitoUserPoUserPoolDomain: 
    Type: AWS::Cognito::UserPoolDomain 
    Properties:
      UserPoolId: !Ref UserPool 
      Domain: !Sub ${AppName}-${Env}

  FacebookCognitoUserPoolIdentityProvider:
    Type: AWS::Cognito::UserPoolIdentityProvider
    Properties:
      ProviderName: Facebook
      AttributeMapping:
        email: email
      ProviderDetails:
        client_id: TODOYourFacebookAppId
        client_secret: TODOYourFacebookAppSecret
        authorize_scopes: email,public_profile
      ProviderType: Facebook
      UserPoolId: !Ref UserPool
    
  GoogleCognitoUserPoolIdentityProvider:
    Type: AWS::Cognito::UserPoolIdentityProvider
    Properties:
      ProviderName: Google
      AttributeMapping:
        email: email
      ProviderDetails:
        client_id: TODOYourGoogleAppId
        client_secret: TODOYourGoogleAppSecret
        authorize_scopes: email openid profile
      ProviderType: Google
      UserPoolId: !Ref UserPool
Arrington answered 16/3, 2021 at 18:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.