Google Sign-In with Amazon Cognito and Next.js
1. Setting Up Amazon Cognito User Pool
Cognito Console:
- Go to Amazon Cognito Console, select
Create user pool
.
- Go to Amazon Cognito Console, select
Configure Sign-In Experience:
Select
Federated identity providers
.Choose
Email
as the minimum sign-in option.Under
Federated sign-in options
, selectGoogle
.
Configure Security Requirements:
Use default
Password policy
.Select
No MFA
for Multi-Factor Authentication.
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.
App Integration:
Enter the user pool name and Cognito domain name.
Select
Confidential client
, and enter an app client name.Add
http://localhost:3000/api/auth/callback
toAllowed callback URLs
.
Create User Pool:
- Review settings and create the user pool.
2. Registering Application on Google Cloud Platform
Google Cloud Platform Console:
- Log in, select
NEW PROJECT
, and set the project name.
- Log in, select
Configure OAuth Consent Screen:
Choose
External
, thenCREATE
.Enter App Information and domain details, add
amazoncognito.com
.
Configure OAuth Scopes:
- Add the following OAuth scopes:
userinfo.email
,userinfo.profile
,openid
.
- Add the following OAuth scopes:
Test Users:
- Add test user email addresses.
Create OAuth Client ID:
Select
Web application
, enter a client name.Add the following URIs to
Authorized Javascript origins
:https://<your-user-pool-domain>
http://localhost:3000
(for local testing, adjust based on your port)
Add
https://<your-user-pool-domain>/oauth2/idpresponse
toAuthorized 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
Select User Pool:
- Go to the Amazon Cognito Console and select the created user pool.
Add Social Identity Provider:
Under
Federated identity provider sign-in
, selectAdd identity provider
, then chooseGoogle
.Enter the Google Client ID and Secret, and add
profile email openid
.
Attribute Mapping:
- Map Google attribute
email
to the Cognito attribute.
- Map Google attribute
App Client Settings:
- In the
App integration
tab, select the app client, then inHosted UI
settings, chooseGoogle
.
- In the
4. Implementing Google Sign-In
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>
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()}`) }
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 }) } }