Sign in with Google

Coming from Google’s documentation after expecting this to be easy? Yah, me too.

Here’s how to add Sign-in with Google to your website

{
  "id": "1be02c41-4d4e-80d4-9633-c2e533849af5",
  "type": "image",
  "url": "https://prod-files-secure.s3.us-west-2.amazonaws.com/a0e28483-01ab-4009-81c1-3139fd1424a5/500f628c-a9b2-4a0e-b0db-258a0f5183b8/CleanShot_2025-03-22_at_15.29.10.png?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Content-Sha256=UNSIGNED-PAYLOAD\u0026X-Amz-Credential=ASIAZI2LB4662HVFIYTP%2F20260903%2Fus-west-2%2Fs3%2Faws4_request\u0026X-Amz-Date=20260903T065903Z\u0026X-Amz-Expires=3600\u0026X-Amz-Security-Token=IQoJb3JpZ2luX2VjEA8aCXVzLXdlc3QtMiJGMEQCIBbbnorioKhTZXvlLG%2BSN4j44ac7j6eJ%2B5QkOxwsQq1AAiBwIErThpiMgexR8c2bCk9j1O%2BheYR1jvrlzGOd9HHDfSqIBAjY%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDYzNzQyMzE4MzgwNSIMF7gi8pFPBeveuqKYKtwD30d3x2P1a1EZUwKjPShFTs7EJwyKl5dDPNgFMrGrSCsYcmydKyUYrGo82JDDMOHsMRqvjX8zLh1cl3qBJkrp6mfKSEX4av%2FJKjRIk07xk9oRiCD0ysMszvPWzd5nLMH%2BbPWrUvZG1H%2BMPHSdYva2nZo9rVObsmuLLjB47cKbcJNuoaoOwSY3KO%2BKyN23C%2FPwV6Op5SKJTMZtg3dblVgvXCEAwM1mT6QLW7nAQAEFgBvUhpxbGBXrTBpVBzj77VueO5GrrNoJUVqW1aqXcvgv9TrWiDrrLCoijBDddn5sWbAYq56%2BJXzDNMbd8%2FjzsAVMQ%2BCUjIurXYQl%2FxuYsDEv95KE75yesDDchcJzSXqAKCM8N5qI43emjIjYeLqygJQZF4ZEpA7hWmIq2TFABny41w3Kt20vjeQW9gCML753S501Iq%2FxXbe7X0wxAO3Q58jdgeVW%2BO0ZBlMARN%2BcT0aooH0JR0ehVJjOSCHU0reTSgshFo5prl4Wn3mqoYnQWR5JvMcD3GZVZ6t69jInEEr5Xp4UhXDbtrB1F6mQC2mKY3vUEA%2BfPTlTjAUILCMZDyjHwCLVfjqwu130hk3jzXGwZoRVtt2NUyARcXOoylp6w87nXkoEZAVVXbzk%2BBEw%2Bavk1AY6pgE9NhCJHMA1qzwShggOdfqjkML2w8X3H1%2BrwREZGPp97NKGjlWcpweDmQ%2FMERA1Pj9rCX3oBjw1B4U8v9ThRB3XKLN2%2BRoSX%2BAWH0PkrNx2AUqiKYRK4R70IUKDpEaCVqt4Z58%2BhKpRW74ZY8kgf637xqnecNFHcjlkqHDDeoqMwlrvukh8x4rkG9w%2Ba6c01uCH2v4L3dtz61ctllW6yld7A8zPt8p7\u0026X-Amz-Signature=67773907301dbed66c54f88ba9c795157d8ada517cf1f16c46281770757e8481\u0026X-Amz-SignedHeaders=host\u0026x-amz-checksum-mode=ENABLED\u0026x-id=GetObject"
}

<script src="https://accounts.google.com/gsi/client" async defer></script>

{
  "id": "1be02c41-4d4e-800a-abea-e0774ac4fc40",
  "type": "code",
  "content": [
    {
      "type": "text",
      "content": "\t\t\u003cdiv\n\t\t\tid=\"g_id_onload\"\n\t\t\tdata-client_id={ env.GOOGLE_CLIENT_ID }\n\t\t\tdata-login_uri={ env.GOOGLE_REDIRECT_URL }\n\t\t\tdata-auto_prompt=\"true\"\n\t\t\tdata-cancel_on_tap_outside=\"false\"\n\t\t\u003e\u003c/div\u003e"
    }
  ],
  "language": "javascript"
}

Creates a POST request to login_uri

https://developers.google.com/identity/gsi/web/guides/verify-google-id-token#node.js

{
  "id": "1be02c41-4d4e-802e-9fdc-d43474cb97e0",
  "type": "code",
  "content": [
    {
      "type": "text",
      "content": "\ttoken, err := r.Cookie(\"g_csrf_token\")\n\tif err != nil {\n\t\thttp.Error(w, \"token not found\", http.StatusBadRequest)\n\t\treturn\n\t}\n\tbodyToken := r.FormValue(\"g_csrf_token\")\n\tif token.Value != bodyToken {\n\t\thttp.Error(w, \"token mismatch\", http.StatusBadRequest)\n\t}\n\n\tcredential := r.FormValue(\"credential\")\n\tpayload, err := idtoken.Validate(r.Context(), credential, c.env.GOOGLE_CLIENT_ID)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusBadRequest)\n\t}\n\n\tfor k, v := range payload.Claims {\n\t\tfmt.Printf(\"%v: %v\\n\", k, v)\n\t}\n\tfmt.Println(\"got request\", payload.Subject)\n"
    }
  ],
  "language": "javascript"
}

sub is the unique ID you should be storing in your database

Don’t use email as an identifier because a Google account can have multiple emails at different points in time