Integrating Google Sign-In with AWS Cognito for Seamless Authentication

Overview

This document provides a detailed guide on integrating Google sign-up and sign-in functionality with AWS Cognito. The integration allows users to authenticate using their Google accounts while maintaining a unified user management system through AWS Cognito.

Architecture

The solution uses the following AWS components:

  • AWS Cognito User Pool: Core authentication service
  • AWS Cognito Identity Provider: Configuration for Google authentication
  • AWS Cognito User Pool Domain: Custom domain for authentication endpoints
  • AWS Cognito User Pool Client: Client application that uses the authentication
  • AWS Lambda: Trigger function to handle the pre-sign-up process for social login

Prerequisites

  1. A Google Developer account and project
  2. Google OAuth credentials (client ID and client secret)
  3. AWS account with appropriate permissions
  4. AWS SSM (Systems Manager Parameter Store) for securely storing credentials

Implementation Steps

  1. Obtain Google OAuth Credentials:
    Request your Google client ID and client secret from your DevOps team. These credentials are essential for enabling the OAuth authentication flow between Google and AWS Cognito.

  2. Add Google Identity Provider to Cognito:
    Create a Google Identity Provider in your Cognito User Pool using CloudFormation:

    #(serverless.yml)
    # Create a separate Google Identity Provider resource
    GoogleIdentityProvider:
      Type: AWS::Cognito::UserPoolIdentityProvider
      Properties:
        UserPoolId: !Ref customersUsersPool
        ProviderName: Google
        ProviderType: Google
        ProviderDetails:
          client_id: ${ssm:GOOGLE_CLIENT_ID}
          client_secret: ${ssm:GOOGLE_CLIENT_SECRET}
          authorize_scopes: email profile openid
        AttributeMapping:
          email: email
          email_verified: email_verified
          picture: picture
          phone_number: phoneNumbers
          profile: picture
          name: name
          gender: genders
    

    This configuration:

    • Links your Cognito User Pool with Google OAuth
    • Requests email, profile, and OpenID scopes
    • Maps Google user attributes to Cognito user attributes.
  3. Create or Attach a Cognito Domain:
    To enable authentication, you have two options:

    • Use a Cognito-Provided Domain (Default Option):
      AWS provides a default domain in the following format:

      https://<your-domain>.auth.<region>.amazoncognito.com
      

      Steps to Configure:

      • Define the Cognito domain in your serverless file:
      CognitoDomain:
        Type: AWS::Cognito::UserPoolDomain
        Properties:
           Domain: ${self:provider.stage}-customer-domain
           UserPoolId: !Ref customersUsersPool
      
      • This will create a domain like:
       https://dev-customer-domain.auth.ap-south-1.amazoncognito.com
      
    • Attach a Custom Domain (Branded Experience):
      If you want a branded authentication experience, you can attach a custom
      domain like:

      https://auth.yourcompany.com
      

      This requires:

      • A domain registered in Route 53 or another domain provider.
      • An SSL certificate in AWS Certificate Manager (ACM).
      • Mapping your custom domain to the Cognito service using a CNAME record

      Steps to Configure:

      • Create a custom domain in Cognito:
      CustomCognitoDomain:
       Type: AWS::Cognito::UserPoolDomain
       Properties:
         Domain: auth.yourcompany.com
         UserPoolId: !Ref customersUsersPool
         CustomDomainConfig:
           CertificateArn: arn:aws:acm:region:account-id:certificate/certificate-id
      
      • In Route 53 or your DNS provider, create a CNAME record to map

      • Add this URL to:

        • Google OAuth Console → Authorized Redirect URIs
        • Cognito User Pool Client settings → CallbackURLs
  4. Configure User Pool Client
    Configure your Cognito User Pool Client to use the Google Identity Provider:

    # Cognito Client
    customersClient:
     Type: AWS::Cognito::UserPoolClient
     DependsOn: [GoogleIdentityProvider, CognitoDomain]
     Properties:
       AccessTokenValidity: 60
       AllowedOAuthFlowsUserPoolClient: true
       AuthSessionValidity: 5
       ClientName: customers-${self:provider.stage}
       UserPoolId: { Ref: customersUsersPool }
       EnablePropagateAdditionalUserContextData: false
       EnableTokenRevocation: true
       ExplicitAuthFlows:
         - ALLOW_CUSTOM_AUTH
         - ALLOW_REFRESH_TOEN_AUTH
         - ALLOW_USER_SRP_AUTH
         - ALLOW_USER_PASSWORD_AUTH
         - ALLOW_ADMIN_USER_PASSWORD_AUTH
         - SupportedIdentityProviders:
         - "COGNITO"
         - "Google"
       AllowedOAuthFlows:
         - implicit
         - code
       AllowedOAuthScopes:
         - openid
         - profile
         - email
         - aws.cognito.signin.user.admin
       CallbackURLs:
         - "${ssm:CUSTOMER_DOMAIN}/"
         - "${ssm:CUSTOMER_DOMAIN}/auth"
         - "https://${self:provider.stage}-customer-domain.auth.${self:provider.region}.amazoncognito.com/oauth2/idpresponse"
         - "http://localhost:3000/"
         - "http://localhost:3000/auth"
       LogoutURLs:
         - "${ssm:CUSTOMER_DOMAIN}/auth"
         - "http://localhost:3000/auth"
         - "${ssm:CUSTOMER_DOMAIN}/"
         - "http://localhost:3000/"
       IdTokenValidity: 5
       PreventUserExistenceErrors: ENABLED
       RefreshTokenValidity: 365
       TokenValidityUnits:
         AccessToken: minutes
         IdToken: minutes
         RefreshToken: days
    

    Key configurations here include:

    • Supported identity providers (including Google)
    • Allowed OAuth flows and scopes
    • Callback and logout URLs
    • Token validity periods
  5. Create Lambda Trigger for Pre-Signup:
    Define a Lambda function that will be triggered during the pre-sign-up process:

    # SOCIAL PRE SIGNUP TRIGGER
    social-pre-signup-trigger:
      handler: social_presignup.handler
      runtime: nodejs18.x
      layers:
        - ${ssm:COMMON_LIB_ARN}
      events:
        - cognitoUserPool:
            pool: customers-${self:provider.stage}
            trigger: PreSignUp
            existing: true
    
  6. Implement Pre-Signup Lambda Function:
    The pre-signup Lambda function handles account linking and user creation. Here’s what it does:

    • Checks if the trigger source is from an external provider (Google)
    • Searches for existing users with the same email
    • If an existing user is found, links the Google identity to that user
    • If no existing user is found, creates a new user and links the Google identity

    The function implements the following workflow:

    • Parse identity provider information
    • Handle potential multiple accounts with the same email (takes the oldest account)
    • Link social login to Cognito user
    • Set secure random passwords for new users

User Flow

  1. The user navigates to your application and selects “Sign in with Google”

  2. The user is redirected to Google’s authentication page

  3. After successful Google authentication, the user is redirected back to your application

  4. The pre-signup Lambda function processes the authentication event:

    • For new users: creates a new Cognito user and links it to the Google identity
    • For existing users: links the Google identity to the existing Cognito user
  5. The user is authenticated in your application

Security Considerations

  • Store Google client ID and secret securely in AWS SSM Parameter Store
  • Configure appropriate OAuth scopes to limit access to user data
  • Set reasonable token validity periods
  • Implement proper error handling for account-disabled scenarios.

Troubleshooting

Common issues and solutions:

  1. Authentication errors:

    • Verify Google client ID and secret

    • Check allowed callback URLs in both Google OAuth settings and Cognito client configuration

    • Ensure that the redirect URIs configured in Google Cloud Console include:

      • The Cognito domain (if applicable):

        https://your-cognito-domain.auth.{region}.amazoncognito.com/oauth2/idpresponse
        
      • The custom Cognito domain (if applicable):

        https://your-custom-domain/oauth2/idpresponse
        
      • Local test environments:

        http://localhost:3000/
        http://localhost:3000/auth
        
  2. Account linking issues:

    • Review the pre-sign-up Lambda logs
    • Verify the provider information is correctly parsed
  3. User not being created:

    • Check Lambda execution permissions to ensure it has access to modify users.
    • Verify the required user attributes are properly mapped.
    • Ensure that the email from the external provider (Google) matches an existing user if linking accounts.
  4. Google OAuth Redirect URI Issues:

    • If users see an error like “redirect_uri_mismatch”, check the Google OAuth Console settings:

      • Ensure all Cognito authentication domains (both default and custom) are listed in the Authorized Redirect URIs.
      • If a custom domain is used, update Google OAuth settings to include it.
    • Confirm that Cognito’s callback URLs match exactly with what is configured in Google Console.

Conclusion:

This integration provides a seamless sign-up and sign-in experience using Google accounts while maintaining centralized user management through AWS Cognito. The pre-signup Lambda function handles account linking and creation automatically, providing a unified authentication system regardless of whether users sign up with email/password or Google.

5 Likes