How to Verify a Facebook OAuth Email in AWS Cognito


Borislav Hadzhiev

Last updated: Apr 21, 2021


Check out my new book

Table of Contents #

  1. Facebook OAuth Emails are NOT Verified in Cognito
  2. Verifying Facebook OAuth Emails in Cognito
  3. Code for the Post Authentication Lambda Trigger
  4. Discussion

Facebook OAuth Emails are NOT Verified in Cognito #

When using Facebook OAuth by default the email_verified attribute is set to false.

By setting the email_verified attribute to true we can use functionality like Forgotten Password for cognito native (email) accounts that are linked to the Facebook OAuth account.

Verifying Facebook OAuth Emails in Cognito #

According to AWS Support the best way to handle Facebook email verification is by using the Post Authentication Lambda trigger - support comment

AWS Cognito invokes the Post Authentication Lambda trigger after a user signs in. In the function we would have to update the email_verified attribute using the AdminUpdateUserAttributes API.

It's important to note that, as the name Post Authentication suggests, this trigger is ran every time the user logs in.

It would be more natural to handle something like this in the Post Confirmation Lambda Trigger, which runs only after a user has successfully been registered. However that wouldn't work because you would get a race condition

Let's see how we can implement the Post Authentication Lambda trigger.

Code for the Post Authentication Lambda Trigger #

Let's define the email confirmation lambda function:

import AWS from 'aws-sdk'; import {Callback, Context, PostAuthenticationTriggerEvent} from 'aws-lambda'; import {adminUpdateUserAttributes} from './admin-update-user-attributes'; const adminUpdateUserAttributes = async ({ userPoolId, username, }: { userPoolId: string; username: string; }): Promise<AWS.CognitoIdentityServiceProvider.AdminUpdateUserAttributesResponse> => { const params = { UserPoolId: userPoolId, Username: username, UserAttributes: [{Name: 'email_verified', Value: 'true'}], }; const cognitoIdp = new AWS.CognitoIdentityServiceProvider(); return cognitoIdp.adminUpdateUserAttributes(params).promise(); }; export async function main( event: PostAuthenticationTriggerEvent, _context: Context, callback: Callback, ): Promise<void> { const {userPoolId, userName} = event; console.log('POST CONFIRMATION EVENT', JSON.stringify(event, null, 2)); if ( { const identities = event.request?.userAttributes?.identities; const isExternalUser = /providername.*facebook/gi.test(identities) || /providername.*google/gi.test(identities); if (isExternalUser) { try { await adminUpdateUserAttributes({ userPoolId, username: userName, }); return callback(null, event); } catch (error) { console.log( 'POST AUTHENTICATION ERROR: ', JSON.stringify(error, null, 2), ); return callback(error, event); } } } return callback(null, event); }

We basically check if the user who's signing in is External (i.e. Facebook or Google - you can only check for the one you use).

If the user is external, we call adminUpdateUserAttributes, which sets the email_verified property to true.

If the user is not an external one, we just return the callback, without doing anything.

The Lambda trigger requires the cognito-idp:AdminUpdateUserAttributes action to call the necessary API.

This policy grants the necessary permissions:

{ "Version": "2012-10-17", "Statement": [ { "Action": "cognito-idp:AdminUpdateUserAttributes", "Resource": "YOUR_USER_POOL_ARN", "Effect": "Allow" } ] }

After you've defined the Lambda function you can set it as a Post Authentication Lambda trigger in your User Pool.

post authentication trigger

Discussion #

This is definitely one of the rough edges around cognito as it doesn't make much sense to confirm a user's email every time they log in to your application.

However this is the current way to handle this and at least in my implementation I haven't experienced any issues.

Further Reading #

Use the search field on my Home Page to filter through my more than 3,000 articles.