Raw response from Google (encoded JWT credential):

Decoded ID token payload:

How verification actually works (what your backend used to do)

Decoding above is not verification — it's just base64-decoding the JWT's middle segment. Anyone can craft a fake JWT with any payload they like; decoding it locally proves nothing about who actually sent it.

Real verification checks that Google actually signed the token:

  1. iss is accounts.google.com
  2. aud matches your OAuth client ID
  3. exp hasn't passed
  4. the signature matches Google's public key for the token's kid

Click "Verify with Google" to call Google's tokeninfo endpoint:

GET https://oauth2.googleapis.com/tokeninfo?id_token=<the JWT>

It performs exactly the checks above and only echoes the claims back if they're valid (otherwise it responds with an error_description) — this is the same kind of call your previous backend was making (directly, or via a JWT/JWKS library doing the same check locally instead of calling Google over the network).

End-to-end flow:

  1. Browser loads Google's gsi/client script
  2. User clicks your custom button, which calls google.accounts.id.prompt()
  3. Google's popup authenticates the user and signs a JWT
  4. Google calls your JS callback with the token
  5. Your JS sends that raw token to your backend
  6. Backend verifies signature + claims (via Google's public keys, or the tokeninfo endpoint)
  7. Backend trusts the identity and creates a session/cookie