title: Google OAuth 2.0 failing with Error 400: invalid_request for some client_id, but works well for others in the same project
body: <p>We have some apps (or maybe we should call them a handful of scripts) that use Google APIs to facilitate some administrative tasks. Recently, after making another client_id in the same project, I started getting an error message similar to the one described in <a href="https://stackoverflow.com/q/70008449/1213346">localhost redirect_uri does not work for Google Oauth2 (results in 400: invalid_request error)</a>. I.e.,</p>
  <blockquote>
  <p>Error 400: invalid_request</p>
  <p>You can't sign in to this app because it doesn't comply with Google's
  OAuth 2.0 policy for keeping apps secure.</p>
  <p>You can let the app developer know that this app doesn't comply with
  one or more Google validation rules.</p>
  <p>Request details:</p>
  <p>The content in this section has been provided by the app developer.
  This content has not been reviewed or verified by Google.</p>
  <p>If you’re the app developer, make sure that these request details
  comply with Google policies.</p>
  <p>redirect_uri: urn:ietf:wg:oauth:2.0:oob</p>
  </blockquote>
  <p>How do I get through this error? It is important to note that:</p>
  <ul>
  <li>The OAuth consent screen for this project is marked as &quot;Internal&quot;. Therefore any mentions of Google review of the project, or publishing status are irrelevant</li>
  <li>I do have &quot;Trust internal, domain-owned apps&quot; enabled for the domain</li>
  <li>Another client id in the same project works and there are no obvious differences between the client IDs - they are both &quot;Desktop&quot; type which only gives me a Client ID and Client secret that are different</li>
  <li>This is a command line script, so I use the &quot;copy/paste&quot; verification method as <a href="https://developers.google.com/identity/protocols/oauth2/native-app?hl=en#step-2:-send-a-request-to-googles-oauth-2.0-server" rel="noreferrer">documented here</a> hence the <code>urn:ietf:wg:oauth:2.0:oob</code> redirect URI (copy/paste is the only friendly way to run this on a headless machine which has no browser).</li>
  <li>I was able to reproduce the same problem in a dev domain. I have three client ids. The oldest one is from January 2021, another one from December 2021, and one I created today - March 2022. Of those, only the December 2021 works and lets me choose which account to authenticate with before it either accepts it or rejects it with &quot;Error 403: org_internal&quot; (this is expected). The other two give me an &quot;Error 400: invalid_request&quot; and do not even let me choose the &quot;internal&quot; account. Here are the URLs generated by my app (I use the ruby google client APIs) and the only difference between them is the client_id - <a href="https://accounts.google.com/o/oauth2/auth?access_type=offline&amp;approval_prompt=force&amp;client_id=566372898811-b89vfj17vaqpcd7bat5tdvbdcpbb41li.apps.googleusercontent.com&amp;include_granted_scopes=true&amp;redirect_uri=urn:ietf:wg:oauth:2.0:oob&amp;response_type=code&amp;scope=https://www.googleapis.com/auth/admin.directory.user.readonly%20https://www.googleapis.com/auth/admin.directory.group.readonly%20https://www.googleapis.com/auth/admin.directory.domain.readonly%20https://www.googleapis.com/auth/drive.readonly%20profile%20https://www.googleapis.com/auth/admin.reports.audit.readonly%20https://www.googleapis.com/auth/drive.file" rel="noreferrer">January 2021</a>, <a href="https://accounts.google.com/o/oauth2/auth?access_type=offline&amp;approval_prompt=force&amp;client_id=566372898811-htvr8md883tk25e1t8q7kabacpmh94dc.apps.googleusercontent.com&amp;include_granted_scopes=true&amp;redirect_uri=urn:ietf:wg:oauth:2.0:oob&amp;response_type=code&amp;scope=https://www.googleapis.com/auth/admin.directory.user.readonly%20https://www.googleapis.com/auth/admin.directory.group.readonly%20https://www.googleapis.com/auth/admin.directory.domain.readonly%20https://www.googleapis.com/auth/drive.readonly%20profile%20https://www.googleapis.com/auth/admin.reports.audit.readonly%20https://www.googleapis.com/auth/drive.file" rel="noreferrer">December 2021</a>, <a href="https://accounts.google.com/o/oauth2/auth?access_type=offline&amp;approval_prompt=force&amp;client_id=566372898811-214ho9i7ngt1faa5llusv3j4sigabl14.apps.googleusercontent.com&amp;include_granted_scopes=true&amp;redirect_uri=urn:ietf:wg:oauth:2.0:oob&amp;response_type=code&amp;scope=https://www.googleapis.com/auth/admin.directory.user.readonly%20https://www.googleapis.com/auth/admin.directory.group.readonly%20https://www.googleapis.com/auth/admin.directory.domain.readonly%20https://www.googleapis.com/auth/drive.readonly%20profile%20https://www.googleapis.com/auth/admin.reports.audit.readonly%20https://www.googleapis.com/auth/drive.file" rel="noreferrer">March 2022</a>.</li>
  </ul>
  <p>Here is the part of the code around the authorization flow, and the URLs for the different client IDs are what was produced on the <code>$stderr.puts url</code> line. It is pretty much the same thing as <a href="https://github.com/googleapis/google-auth-library-ruby#example-command-line" rel="noreferrer">documented in the official example here</a> (<a href="https://github.com/googleapis/google-auth-library-ruby/blob/b1b6b18355863cf553e52fbffe23cd42f7b18bf5/README.md#example-command-line" rel="noreferrer">version as of this writing</a>).</p>
  <pre class="lang-rb prettyprint-override"><code>
  OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
  
  def user_credentials_for(scope, user_id = 'default')
      token_store = Google::Auth::Stores::FileTokenStore.new(:file =&gt; token_store_path)
      authorizer = Google::Auth::UserAuthorizer.new(client_id, scope, token_store)
      credentials = authorizer.get_credentials(user_id)
      if credentials.nil?
          url = authorizer.get_authorization_url(base_url: OOB_URI)
          $stderr.puts &quot;&quot;
          $stderr.puts &quot;-----------------------------------------------&quot;
          $stderr.puts &quot;Requesting authorization for '#{user_id}'&quot;
          $stderr.puts &quot;Open the following URL in your browser and authorize the application.&quot;
          $stderr.puts url
          code = $stdin.readline.chomp
          $stderr.puts &quot;-----------------------------------------------&quot;
          credentials = authorizer.get_and_store_credentials_from_code(
              user_id: user_id, code: code, base_url: OOB_URI)
      end
      credentials
  end
                                                                                                                                            
  </code></pre>