{"record":{"id":"c9d6791a061ac63c","repo":"benweet/stackedit","slug":"client-id-inconsistent","errorCode":null,"errorMessage":"Client ID inconsistent.","messagePattern":"Client ID inconsistent\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/services/providers/helpers/googleHelper.js","lineNumber":142,"sourceCode":"        login_hint: sub,\n        prompt: silent ? 'none' : null,\n        nonce: utils.uid(),\n      },\n      silent,\n    );\n\n    // Call the token info endpoint\n    const { body } = await networkSvc.request({\n      method: 'POST',\n      url: 'https://www.googleapis.com/oauth2/v3/tokeninfo',\n      params: {\n        access_token: accessToken,\n      },\n    }, true);\n\n    // Check the returned client ID consistency\n    if (body.aud !== clientId) {\n      throw new Error('Client ID inconsistent.');\n    }\n    // Check the returned sub consistency\n    if (sub && `${body.sub}` !== sub) {\n      throw new Error('Google account ID not expected.');\n    }\n\n    // Build token object including scopes and sub\n    const existingToken = store.getters['data/googleTokensBySub'][body.sub];\n    const token = {\n      scopes,\n      accessToken,\n      expiresOn: Date.now() + (expiresIn * 1000),\n      idToken,\n      sub: body.sub,\n      name: (existingToken || {}).name || 'Someone',\n      isLogin: !store.getters['workspace/mainWorkspaceToken'] &&\n        scopes.includes('https://www.googleapis.com/auth/drive.appdata'),\n      isSponsor: false,","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/benweet/stackedit/blob/6dce2a5e36b755a0c244522b48a06c91a2df0f59/src/services/providers/helpers/googleHelper.js#L124-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Discard old tokens and re-run the full sign-in flow with the correct client ID.","Check environment config (env vars/build constants) so staging and prod use their own client IDs consistently.","If you migrated Google Cloud projects, re-issue tokens under the new client and invalidate stored ones."],"exampleFix":"// before\nconst token = await googleHelper.startOauth2(code, sub, clientIdFromOldConfig);\n// after\nconst token = await googleHelper.startOauth2(code, sub, constants.googleClientId); // same ID used in the auth URL\n","handlingStrategy":"validation","validationCode":"const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;\nif (!GOOGLE_CLIENT_ID || !/^[0-9a-zA-Z-]+\\.apps\\.googleusercontent\\.com$/.test(GOOGLE_CLIENT_ID)) {\n  throw new Error('GOOGLE_CLIENT_ID missing or malformed');\n}\nif (GOOGLE_CLIENT_ID !== clientIdUsedInAuthUrl) throw new Error('Client ID mismatch between auth URL and token validation');","typeGuard":"function isAudienceValid(idTokenBody, clientId) {\n  return typeof idTokenBody.aud === 'string' && idTokenBody.aud === clientId;\n}","tryCatchPattern":"try {\n  const token = await googleHelper.startOauth2(code, sub, clientId);\n} catch (err) {\n  if (err.message === 'Client ID inconsistent.') {\n    // config/env mismatch: reload correct clientId and invalidate old tokens\n  } else throw err;\n}","preventionTips":["Keep a single source of truth for the Google client ID used in both auth URL and validation","Invalidate stored tokens when rotating client IDs or switching Google Cloud projects","Separate client IDs per environment (staging/prod) and verify env vars at startup","Log the expected vs received aud on failure to speed diagnosis"],"tags":["google","oauth2","client-id","id-token","audience-mismatch"],"backgroundTag":"oauth-audience-mismatch","analyzedSha":"6dce2a5e36b755a0c244522b48a06c91a2df0f59","analyzedAt":"2026-09-01T00:49:23.866Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}