Save AWS Cognito Users in DynamoDB

4.7k Views Asked by At

I recently started experimenting with AWS AppSync but I had some questions around AWS Cognito.

I would like for users to be able to authenticate with Facebook but I need their profile picture, name and email as data for my public user profiles in my app. So far, I noticed Cognito integrates with Facebook Auth but it does not allow access to the user information and this info does not get saved in a DynamoDB table.

My question is, how can I create a new User in DynamoDB when Cognito receives a new sign in, or return an existing user/id when the user already exists in the db.

3

There are 3 best solutions below

4
On

I was trying to achieve the same a few weeks ago.

After reading the docs for hours, I realised that Cognito may not help us in regards to the data that comes back from FB or how to save it.

I ended up doing the following:

(1) Using FB-SDK, pulled in the user data.

(2) Invoked a Lambda function that saved this data (like FB_id,etc) to DynamoDB.

(3) If user logged in again, their FB_id (or email) was used to check against DynamoDB entries to retrieve their data.

If Cognito is able to help us and I missed it somehow, I would love to know.

Happy Coding!

0
On

You could use custom attributes and federating user from Facebook in your user pool to achieve this. Here are the steps at high level to do this.

  • You will first have to define custom attributes for the profile information you want to save in each user profile.
  • Define attribute mapping to link the custom attributes to Facebook attributes you want to save.
  • Build you application using Cognito hosted pages and federation to allow your users to log in using Facebook.

After this, on each new user log in in your app a new user is created in your user pool with all the attributes that were defined in attribute mapping and values which Cognito gets in the Facebook token. Your app will get these attribute values in the IDToken issued after authentication and you app can use these.

Additionally, if you want to store these attribute values outside of Cognito user pools profile, like your own DynamoDB table, you can configure a PreSignUp trigger in the pool which will be invoked on all new user creations. You can export the user attributes from this trigger to any database of your choice.

Hope this helps.

0
On

AWS AppSync allows you to access information in the GraphQL resolver which you can choose to store in a DynamoDB table. In your case for data coming from a Facebook profile you could pass this as arguments to a GraphQL mutation or in a header to AppSync which you can then access in the resolver via $ctx.request.headers.NAME where NAME is your header name. Then you could simply choose which attributes you want to write to DynamoDB for that user as part of the mutation. More information is in the reference guide here: https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html

Since you also asked that you'd like to do a check first to see if the user is already in the DDB first you could just do an existence check first:

{
  "version": "2017-02-28",
  "operation": "PutItem",
  "key": {
    "userId": $util.dynamodb.toDynamoDBJson($ctx.identity.username),
  },
  "attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input),
  "condition": {
    "expression": "attribute_not_exists(userId)"
  },
}

This checks against the username from Cognito User Pools. If you were using the Cognito Federated Identities feature it would be ctx.identity.cognitoIdentityId. If the record is already there the response that comes back will tell you which means the user is already present. You could also transform the returned message in the response mapping template by looking at $ctx.result with a conditional statement and either building the JSON response by scratch or using one of the $util.error() methods in the guide above.

Finally as you mentioned that you'll have public profile data, you might want to mark this on certain records for control. In AWS AppSync you can filter GraphQL responses on authorization metadata such as this. You would just have an attribute (aka column) on the DynamoDB record marked 'public' or 'private. Then your response template would look like so:

#if($context.result.public == 'yes')
    $utils.toJson($context.result)
#else
    $utils.unauthorized()
#end

You can see more examples of this here: https://docs.aws.amazon.com/appsync/latest/devguide/security-authorization-use-cases.html#public-and-private-records