benweet/stackedit · error · Error

Client ID inconsistent.

Error message

Client ID inconsistent.

What it means

Google's OAuth2 ID token contains an 'aud' (audience) claim that must equal the OAuth client ID that requested it. startOauth2 validates body.aud against clientId and throws 'Client ID inconsistent.' when they differ, defending against tokens minted for a different OAuth client being accepted.

Source

Thrown at src/services/providers/helpers/googleHelper.js:142

        login_hint: sub,
        prompt: silent ? 'none' : null,
        nonce: utils.uid(),
      },
      silent,
    );

    // Call the token info endpoint
    const { body } = await networkSvc.request({
      method: 'POST',
      url: 'https://www.googleapis.com/oauth2/v3/tokeninfo',
      params: {
        access_token: accessToken,
      },
    }, true);

    // Check the returned client ID consistency
    if (body.aud !== clientId) {
      throw new Error('Client ID inconsistent.');
    }
    // Check the returned sub consistency
    if (sub && `${body.sub}` !== sub) {
      throw new Error('Google account ID not expected.');
    }

    // Build token object including scopes and sub
    const existingToken = store.getters['data/googleTokensBySub'][body.sub];
    const token = {
      scopes,
      accessToken,
      expiresOn: Date.now() + (expiresIn * 1000),
      idToken,
      sub: body.sub,
      name: (existingToken || {}).name || 'Someone',
      isLogin: !store.getters['workspace/mainWorkspaceToken'] &&
        scopes.includes('https://www.googleapis.com/auth/drive.appdata'),
      isSponsor: false,

View on GitHub (pinned to 6dce2a5e36)

Solutions

  1. Ensure the clientId passed to startOauth2 exactly matches the client ID used to create the auth request (same Google Cloud project, no trailing/leading whitespace).
  2. Discard old tokens and re-run the full sign-in flow with the correct client ID.
  3. Check environment config (env vars/build constants) so staging and prod use their own client IDs consistently.
  4. If you migrated Google Cloud projects, re-issue tokens under the new client and invalidate stored ones.

Example fix

// before
const token = await googleHelper.startOauth2(code, sub, clientIdFromOldConfig);
// after
const token = await googleHelper.startOauth2(code, sub, constants.googleClientId); // same ID used in the auth URL
Defensive patterns

Strategy: validation

Validate before calling

const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;
if (!GOOGLE_CLIENT_ID || !/^[0-9a-zA-Z-]+\.apps\.googleusercontent\.com$/.test(GOOGLE_CLIENT_ID)) {
  throw new Error('GOOGLE_CLIENT_ID missing or malformed');
}
if (GOOGLE_CLIENT_ID !== clientIdUsedInAuthUrl) throw new Error('Client ID mismatch between auth URL and token validation');

Type guard

function isAudienceValid(idTokenBody, clientId) {
  return typeof idTokenBody.aud === 'string' && idTokenBody.aud === clientId;
}

Try / catch

try {
  const token = await googleHelper.startOauth2(code, sub, clientId);
} catch (err) {
  if (err.message === 'Client ID inconsistent.') {
    // config/env mismatch: reload correct clientId and invalidate old tokens
  } else throw err;
}

Prevention

When it happens

Trigger: OAuth callback (token), signin, or refreshToken when the ID token's aud claim does not equal the configured Google client ID — e.g. clientId config changed between token issuance and validation, or the token came from a different app's client.

Common situations: Deploying with a mismatched GOOGLE_CLIENT_ID env var; rotating client IDs but keeping old refresh tokens; multiple environments (staging/prod) sharing stored tokens; copy-pasting a client ID from another Google Cloud project.

Related errors


AI-assisted analysis of benweet/stackedit@6dce2a5e36 (2026-09-01). Data as JSON: /api/errors/c9d6791a061ac63c. Report an issue: GitHub.