Google Sign-In with Amazon Cognito and Next.js

·

3 min read

1. Setting Up Amazon Cognito User Pool

  1. Cognito Console:

    • Go to Amazon Cognito Console, select Create user pool.
  2. Configure Sign-In Experience:

    • Select Federated identity providers.

    • Choose Email as the minimum sign-in option.

    • Under Federated sign-in options, select Google.

  3. Configure Security Requirements:

    • Use default Password policy.

    • Select No MFA for Multi-Factor Authentication.

  4. Configure Sign-Up Experience and Message Delivery:

    • Keep default settings for account recovery and sign-up experience.

    • Select Send email with Cognito for message delivery.

  5. App Integration:

  6. Create User Pool:

    • Review settings and create the user pool.

2. Registering Application on Google Cloud Platform

  1. Google Cloud Platform Console:

    • Log in, select NEW PROJECT, and set the project name.
  2. Configure OAuth Consent Screen:

    • Choose External, then CREATE.

    • Enter App Information and domain details, add amazoncognito.com.

  3. Configure OAuth Scopes:

    • Add the following OAuth scopes: userinfo.email, userinfo.profile, openid.
  4. Test Users:

    • Add test user email addresses.
  5. Create OAuth Client ID:

    • Select Web application, enter a client name.

    • Add the following URIs to Authorized Javascript origins:

    • Add https://<your-user-pool-domain>/oauth2/idpresponse to Authorized redirect URIs.

    • Purpose: This is the endpoint where Cognito processes the authorization code received from Google (after federated authentication).

    • Store the Client ID and Secret securely.


3. Adding Google as a Social Identity Provider to Amazon Cognito User Pool

  1. Select User Pool:

    • Go to the Amazon Cognito Console and select the created user pool.
  2. Add Social Identity Provider:

    • Under Federated identity provider sign-in, select Add identity provider, then choose Google.

    • Enter the Google Client ID and Secret, and add profile email openid.

  3. Attribute Mapping:

    • Map Google attribute email to the Cognito attribute.
  4. App Client Settings:

    • In the App integration tab, select the app client, then in Hosted UI settings, choose Google.

4. Implementing Google Sign-In

  1. Set Environment Variables:

    • Add the following to your .env.local file:

        COGNITO_DOMAIN=<your-cognito-domain>
        COGNITO_APP_CLIENT_ID=<your-app-client-id>
        COGNITO_APP_CLIENT_SECRET=<your-app-client-secret>
      
  2. Implement Authorize Endpoint:

    • Create an API route to redirect users to the Google Sign-In page:

        // app/api/auth/google-sign-in/route.ts
        import { NextRequest, NextResponse } from "next/server"
        import crypto from 'crypto'
      
        const { COGNITO_DOMAIN, COGNITO_APP_CLIENT_ID } = process.env
      
        export async function GET(request: NextRequest) {
            let authorizeParams = new URLSearchParams()
            const origin = request.nextUrl.origin
      
            const state = crypto.randomBytes(16).toString('hex')
      
            authorizeParams.append('response_type', 'code')
            authorizeParams.append('client_id', COGNITO_APP_CLIENT_ID as string)
            authorizeParams.append('redirect_uri', `${origin}/api/auth/callback`)
            authorizeParams.append('state', state)
            authorizeParams.append('identity_provider', 'Google')
            authorizeParams.append('scope', 'profile email openid')
      
            return NextResponse.redirect(`${COGNITO_DOMAIN}/oauth2/authorize?${authorizeParams.toString()}`)
        }
      
  3. Implement Token Endpoint:

    • Create an API route to obtain tokens using the authorization code:

        // app/api/auth/callback/route.ts
        import { NextResponse, type NextRequest } from 'next/server'
        import { cookies } from 'next/headers'
      
        const {
            COGNITO_DOMAIN,
            COGNITO_APP_CLIENT_ID,
            COGNITO_APP_CLIENT_SECRET
        } = process.env
      
        export async function GET(request: NextRequest) {
            try {
                const origin = request.nextUrl.origin
                const searchParams = request.nextUrl.searchParams
                const code = searchParams.get('code') as string
      
                if (!code) {
                    const error = searchParams.get('error')
                    return NextResponse.json({ error: error || 'Unknown error' })
                }
      
                const authorizationHeader = `Basic ${Buffer.from(`${COGNITO_APP_CLIENT_ID}:${COGNITO_APP_CLIENT_SECRET}`).toString('base64')}`
      
                const requestBody = new URLSearchParams({
                    grant_type: 'authorization_code',
                    client_id: COGNITO_APP_CLIENT_ID as string,
                    code: code,
                    redirect_uri: `${origin}/api/auth/callback`
                })
      
                const res = await fetch(`${COGNITO_DOMAIN}/oauth2/token`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Authorization': authorizationHeader
                    },
                    body: requestBody
                })
      
                const data = await res.json()
      
                if (!res.ok) {
                    return NextResponse.json({
                        error: data.error,
                        error_description: data.error_description
                    })
                }
      
                // Store tokens in cookies
                const cookieStore = cookies()
                cookieStore.set('id_token', data.id_token)
                cookieStore.set('access_token', data.access_token)
                cookieStore.set('refresh_token', data.refresh_token)
      
                return NextResponse.redirect(new URL('/', request.nextUrl))
            } catch (error) {
                return NextResponse.json({ error: error })
            }
        }
      

THIS LINK IS THE REF POST