yikart/AiToEarn · error · Error

Invalid Google token

Error message

Invalid Google token

What it means

googleLogin verifies a Google ID token with google-auth-library's OAuth2Client.verifyIdToken. After verification, ticket.getPayload() must return the decoded claims; if it returns null/undefined the token cannot be trusted and the service throws Error('Invalid Google token'). This guards against empty or malformed tokens reaching the login flow.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/google/google.service.ts:403

  /**
   * Google登录
   * @param clientId Google客户端ID
   * @param credential Google认证凭证
   * @returns Account
   */
  async googleLogin(clientId: string, credential: string): Promise<any> {
    try {
      console.log('Verifying Google token with:');
      // 验证Google token
      const ticket = await this.oauth2Client.verifyIdToken({
        idToken: credential,
        audience: clientId,
      });
      console.log('ticket',ticket)
      const googleUser = ticket.getPayload();
      console.log('payload',googleUser)
      if (!googleUser) {
        throw new Error('Invalid Google token');
      }

      console.log('Google login success, googleUser:', googleUser);

      const googleAccount = {
        googleId: googleUser.sub,
        email: googleUser.email,
        // accessToken: result.data.access_token,
        refreshToken: null,
        // expiresAt: result.data.expires_in
      };

      let userInfo: User | null = null;
      // 优先用 Google ID 查找(最准确)
      if (googleUser.sub) {
        userInfo = await this.userModel.findOne({
          'googleAccount.googleId': googleUser.sub,
          status: UserStatus.OPEN,

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Check the client is sending the real Google ID token (credential/id_token), not an access token or empty string
  2. Verify the clientId passed as audience matches the OAuth client that issued the token
  3. Validate the token string is non-empty before calling googleLogin
  4. Upgrade google-auth-library to the latest version
  5. Catch this in the controller and return 401 instead of a raw 500

Example fix

// before
if (!googleUser) {
  throw new Error('Invalid Google token');
}
// after
if (!googleUser || !googleUser.sub || !googleUser.email) {
  throw new UnauthorizedException('Invalid or incomplete Google token payload');
}
Defensive patterns

Strategy: validation

Validate before calling

if (typeof idToken !== 'string' || idToken.split('.').length !== 3) {
  throw new UnauthorizedException('A valid Google id_token is required');
}

Type guard

function hasGooglePayload(t: unknown): t is { sub: string; email: string } {
  return !!t && typeof t === 'object' && 'sub' in t && typeof (t as any).sub === 'string';
}

Try / catch

try {
  await authService.googleLogin(idToken, clientId);
} catch (err) {
  if (err.message.includes('Invalid Google token')) {
    return res.status(401).json({ error: 'Please sign in with Google again' });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling googleLogin with an idToken that is empty, malformed, or decodes to no payload — i.e. verifyIdToken resolves but getPayload() returns falsy.

Common situations: Frontend sends an empty string token when the user aborted Google Sign-In; wrong clientId/audience causing an unexpected payload shape; passing an access_token instead of an id_token; an outdated google-auth-library version behaving differently.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/30e8089ee815735a. Report an issue: GitHub.