Building AWS Cognito PreSignup Lambda on DotNet

Using .Net Core 1.0 Lambda I want to be able to create a Lambda function that handles a PreSignUp trigger from the AWS Cognito user pool.

using Amazon.Lambda.Core;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

public class PreSignUp_SignUp
{
  public string userPoolId { get; set; }
  public const string EmailKey = "email";
  public const string PhoneNumber = "phone_number";
  public Dictionary<string,string> userAttributes { get; set; }
  public Dictionary<string, string> validationData { get; set; }
}

public class PreSignup_SignUpResponse
{
  public bool autoConfirmUser { get; set; }
}

public class Function
{
  public PreSignup_SignUpResponse FunctionHandler(PreSignUp_SignUp input, ILambdaContext context)
  {
      return new PreSignup_SignUpResponse { autoConfirmUser = true };
  }
}

      

Although the request succeeds and returns a response when calling Lambda with an example request:

{
  "datasetName": "datasetName",
  "eventType": "SyncTrigger",
  "region": "us-east-1",
  "identityId": "identityId",
  "datasetRecords": {
    "SampleKey2": {
      "newValue": "newValue2",
      "oldValue": "oldValue2",
      "op": "replace"
    },
    "SampleKey1": {
      "newValue": "newValue1",
      "oldValue": "oldValue1",
      "op": "replace"
    }
  },
  "identityPoolId": "identityPoolId",
  "version": 2
}

      

When executing actual SignUp via .Net AmazonCognitoIdentityProviderClient, I get back an error:

Amazon.CognitoIdentityProvider.Model.InvalidLambdaResponseException: Unrecognizable lambda output

I'm assuming I don't have a response form (and maybe even a request).

Does anyone have an example .Net Lambda function that works for a PreSignUp trigger in AWS Cognito?

+3


source to share


2 answers


The cognito trigger requests / responses must contain all the payload specified in the Cognito trigger documentation:

http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html

I found that when diagnosing this problem, the best place to start is by creating a function handler that takes a JObject and then writes and returns the same object, eg.

public JObject FunctionHandler(JObject input, ILambdaContext context)
{
    context.Logger.LogLine("Input was: " + input);
    return input;
}

      

This grabs the payload in the cloudwatch logs and then helps guide you in a strongly typed structured way.



In my case, for PreSignUp, I created the following types to create a simple function that automatically validates all the provided credentials.

public abstract class AbstractTriggerRequest
{
    [JsonProperty("userAttributes")]
    public Dictionary<string, string> UserAttributes { get; set; }
}

public abstract class AbstractTriggerResponse
{
}

public class TriggerCallerContext
{
    [JsonProperty("awsSdkVersion")]
    public string AwsSdkVersion { get; set; }
    [JsonProperty("clientId")]
    public string ClientId { get; set; }
}

public abstract class AbstractTriggerBase<TRequest, TResponse>
    where TRequest: AbstractTriggerRequest
    where TResponse: AbstractTriggerResponse
{
    [JsonProperty("version")]
    public int Version { get; set; }
    [JsonProperty("triggerSource")]
    public string TriggerSource { get; set; }
    [JsonProperty("region")]
    public string Region { get; set; }
    [JsonProperty("userPoolId")]
    public string UserPoolId { get; set; }  
    [JsonProperty("callerContext")]
    public TriggerCallerContext CallerContext { get; set; }
    [JsonProperty("request")]
    public TRequest Request { get; set; }
    [JsonProperty("response")]
    public TResponse Response { get; set; }
    [JsonProperty("userName", NullValueHandling = NullValueHandling.Ignore)]
    public string UserName { get; set; }
}

public class PreSignUpSignUpRequest : AbstractTriggerRequest
{
    [JsonProperty("validationData")]
    public Dictionary<string,string> ValidationData { get; set; }
}

      

The Lambda function then ends with the following signature:

public class Function
{
    public PreSignUp_SignUp FunctionHandler(PreSignUp_SignUp input, ILambdaContext context)
    {
        context.Logger.LogLine("Auto-confirming everything!");

        input.Response = new PreSignUpSignUpResponse {
            AutoConfirmUser = true,
            // you can only auto-verify email or phone if it present in the user attributes
            AutoVerifyEmail = input.Request.UserAttributes.ContainsKey("email"),
            AutoVerifyPhone = input.Request.UserAttributes.ContainsKey("phone_number") 
        };

        return input;
    }
}

      

Hope this helps someone else to run into problems writing Lambda triggers for Cognito.

+6


source


There is another great answer here. However, I am not an expert .NET developer, so this solution makes more sense to me.



class AutoVerifyEmail
{
    public AutoVerifyEmail() { }

    public JObject AutoVerifyEmailPreSignup(JObject input, ILambdaContext context)
    {
        //Console.Write(input); //Print Input

        input["response"]["autoVerifyEmail"] = true;
        input["response"]["autoConfirmUser"] = true;

        return input;
    }
}

      

+1


source







All Articles