oauth-2.0 Google OAuth 2.0失败,并显示错误400:invalid_request对某些client_id无效,但对同一项目中的其他client_id有效

kx1ctssn  于 2022-10-31  发布在  Go
关注(0)|答案(9)|浏览(172)

我们有一些应用程序(或者我们应该称它们为少数脚本)使用Google API来简化一些管理任务。最近,在同一个项目中制作了另一个client_id后,我开始收到类似于localhost redirect_uri does not work for Google Oauth2 (results in 400: invalid_request error)中描述的错误消息。即,
错误400:无效请求
你无法登录此应用,因为它不符合Google的OAuth 2.0保护应用安全的策略。
您可以让应用程序开发人员知道此应用程序不符合一个或多个Google验证规则。
请求详细信息:
本节内容由应用程序开发者提供。此内容未经Google审查或验证。
如果您是应用程序开发人员,请确保这些请求详细信息符合Google政策。
重定向URI(_U):用户名:用户名:
如何克服此错误?请务必注意:

  • 此项目的OAuth同意屏幕标记为“内部”。因此,任何有关Google审查项目或发布状态的内容都是无关紧要的
  • 我为域启用了“信任内部、域拥有的应用程序”
  • 同一个项目中的另一个客户端ID工作,客户端ID之间没有明显的区别-它们都是“桌面”类型,只给我一个不同的客户端ID和客户端密码
  • 这是一个命令行脚本,因此我使用了这里所述的“复制/粘贴”验证方法,因此使用了urn:ietf:wg:oauth:2.0:oob重定向URI(复制/粘贴是在没有浏览器的无头机器上运行此脚本的唯一友好方法)。
  • 我在一个开发域中重现了同样的问题。我有三个客户端ID。最早的一个是2021年1月的,另一个是2021年12月的,还有一个是我今天创建的--2022年3月。其中,只有2021年12月的ID可以工作,它让我选择用哪个帐户进行身份验证,然后它要么接受它,要么拒绝它,并显示“错误403:org_internal”(这是预期的)。另外两个则给予“错误400:invalid_request”,甚至不让我选择“internal”帐户。以下是我的应用程序生成的URL(我使用Ruby Google客户端API),它们之间唯一的区别是client_id -January 2021December 2021March 2022

下面是授权流程的部分代码,不同客户端ID的URL是在$stderr.puts url行中生成的,与这里的官方示例(撰写本文时的版本)中记录的内容几乎相同。

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 => 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 ""
        $stderr.puts "-----------------------------------------------"
        $stderr.puts "Requesting authorization for '#{user_id}'"
        $stderr.puts "Open the following URL in your browser and authorize the application."
        $stderr.puts url
        code = $stdin.readline.chomp
        $stderr.puts "-----------------------------------------------"
        credentials = authorizer.get_and_store_credentials_from_code(
            user_id: user_id, code: code, base_url: OOB_URI)
    end
    credentials
end
a9wyjsp7

a9wyjsp71#

以下是针对这种情况的一个棘手的解决方法:
将问题中的代码中的urn:ietf:wg:oauth:2.0:oob替换为http://localhost:1/,这样可以使流程通过,我的浏览器被重定向并出现故障,我会收到如下错误消息:

This site can’t be reached

The webpage at http://localhost:1/oauth2callback?
code=4/a3MU9MlhWxit8P7N8QsGtT0ye8GJygOeCa3MU9MlhWxit8P7N8QsGtT0y
e8GJygOeC&scope=email%20profile%20https... might be temporarily
down or it may have moved permanently to a new web address.

ERR_UNSAFE_PORT

现在从失败的URL中复制代码code值,将其粘贴到应用程序中,瞧......与之前相同:)
P.S.以下是更新后的“工作”版本:

def user_credentials_for(scope, user_id = 'default')
    token_store = Google::Auth::Stores::FileTokenStore.new(:file => token_store_path)
    authorizer = Google::Auth::UserAuthorizer.new(client_id, scope, token_store, "http://localhost:1/")
    credentials = authorizer.get_credentials(user_id)
    if credentials.nil?
        url = authorizer.get_authorization_url
        $stderr.puts ""
        $stderr.puts "-----------------------------------------------"
        $stderr.puts "Requesting authorization for '#{user_id}'"
        $stderr.puts "Open the following URL in your browser and authorize the application."
        $stderr.puts url
        $stderr.puts
        $stderr.puts "At the end the browser will fail to connect to http://localhost:1/?code=SOMECODE&scope=..."
        $stderr.puts "Copy the value of SOMECODE from the address and paste it below"

        code = $stdin.readline.chomp
        $stderr.puts "-----------------------------------------------"
        credentials = authorizer.get_and_store_credentials_from_code(
            user_id: user_id, code: code)
    end
    credentials
end                                                                                                                                      ```
kxkpmulp

kxkpmulp2#

我给Google OAuth团队的某个人发了一封电子邮件,这是他们回复的要点。
因为我担心您的问题与通过使用更安全的OAuth流使Google OAuth交互更安全有关
google目前的建议是使用localhost/loopback重定向,如下所示:instructions-oob或使用设备流的OAuth(如果您使用的是非敏感范围并需要无头解决方案)。

c6ubokkw

c6ubokkw3#

一个针对python的解决方案。
正如google_auth_oauthlib所示,InstalledAppFlow.run_console在2022年2月28日之后就被弃用了。如果你使用的是google-ads-python,你可以用flow.run_local_server()替换flow.run_console()

li9yvcax

li9yvcax4#

让我把“适当的”解决方案作为一个单独的答案来发布,即实际上通过在ruby应用程序中实现一个HTTP侦听器来遵循推荐的过程。如果它在脱机计算机上运行,侦听器将永远不会获得代码,但您仍然可以从失败的URL中粘贴代码。

require 'colorize'
require 'sinatra/base'

def run_local_server(authorizer, port, user_id)

    require 'thin'
    Thin::Logging.silent = true

    Thread.new {

        Thread.current[:server] = Sinatra.new do

            enable :quiet
            disable :logging
            set :port, port
            set :server, %w[ thin ]

            get "/" do
                request = Rack::Request.new env
                state = {
                    code:  request["code"],
                    error: request["error"],
                    scope: request["scope"]
                }
                raise Signet::AuthorizationError, ("Authorization error: %s" % [ state[:error] ] ) if state[:error]
                raise Signet::AuthorizationError, "Authorization code missing from the request" if state[:code].nil?
                credentials = authorizer.get_and_store_credentials_from_code(

                    user_id: user_id,
                    code: state[:code],
                    scope: state[:scope],
                )
                [
                    200,
                    { "Content-Type" => "text/plain" },
                    "All seems to be OK. You can close this window and press ENTER in the application to proceed.",
                ]
            end

        end
        Thread.current[:server].run!
    }

end

client_id = Google::Auth::ClientId.new(ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'])
token_store = Google::Auth::Stores::FileTokenStore.new(:file => ENV['GOOGLE_CREDENTIAL_STORE'])
PORT = 6969
redirect_uri = "http://localhost:#{PORT}/"
authorizer = Google::Auth::UserAuthorizer.new(client_id, scope, token_store, redirect_uri)
credentials = authorizer.get_credentials(user_id)
if credentials.nil? then
  server_thread = run_local_server(authorizer, PORT, user_id)
  url = authorizer.get_authorization_url
  $stderr.puts ""
  $stderr.puts "-----------------------------------------------"
  $stderr.puts "Requesting authorization for '#{user_id.yellow}'"
  $stderr.puts "Open the following URL in your browser and authorize the application."
  $stderr.puts
  $stderr.puts url.yellow.bold
  $stderr.puts
  $stderr.puts "⚠️ If you are authorizing on a different machine, you will have to port-forward"
  $stderr.puts "so your browser can reach #{redirect_uri.yellow}"
  $stderr.puts
  $stderr.puts "⚠️ If you get a " << "This site can't be reached".red << " error in the browser,"
  $stderr.puts "just copy the code which is in the code= part of the failing address on the next line."
  $stderr.puts "E.g., you need only the " << "green".bold.green << " part of the address which looks like"
  $stderr.puts "#{redirect_uri}?code=".yellow << "4/QMoyZIyzt8uXO6j...j8ajEEjfd".bold.green << "&scope=email%20profile...".yellow
  $stderr.puts "-----------------------------------------------"
  code = $stdin.readline.chomp
  server_thread[:server].stop!
  server_thread.join
  credentials = authorizer.get_credentials(user_id)
  # If the redirect failed, the user must have provided us with a code on their own
  if credentials.nil? then
    credentials = authorizer.get_and_store_credentials_from_code(user_id: user_id, code: code, scope: scope)
  end
end

简而言之,我们运行一个Web服务器,它接受浏览器发送的代码,或者接受用户粘贴的代码。

kqqjbcuj

kqqjbcuj5#

对于需要敏感作用域的headless Python脚本,继续使用run_console现在会产生以下结果(流程可能会失败):

DeprecationWarning: New clients will be unable to use `InstalledAppFlow.run_console` starting on Feb 28, 2022. All clients will be unable to use this method starting on Oct 3, 2022. Use `InstalledAppFlow.run_local_server` instead. For details on the OOB flow deprecation, see https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html?m=1#disallowed-oob

官方的解决方案是迁移到一个启动本地服务器来处理OAuth重定向的流,但这在远程无头系统上不起作用。
Google在gcloud中采用的解决方案是在用户浏览器所在的机器上运行一个本地服务器,然后让用户将从本地服务器请求的重定向URL复制回远程机器。请注意,这需要在远程机器和用户的工作站上都安装gcloud
当在工作站上安装一个脚本来回显重定向URL不可行时,我们可以使用一个肯定会失败的重定向URL,让用户复制回他们在授权完成后将登陆的错误页面的URL。

import urllib
from google_auth_oauthlib.flow import InstalledAppFlow

def run_console_hack(flow):
    flow.redirect_uri = 'http://localhost:1'
    auth_url, _ = flow.authorization_url()
    print(
        "Visit the following URL:",
        auth_url,
        "After granting permissions, you will be redirected to an error page",
        "Copy the URL of that error page (http://localhost:1/?state=...)",
        sep="\n"
    )
    redir_url = input("URL: ")
    query = urllib.parse.urlparse(redir_url).query
    code = urllib.parse.parse_qs(query)['code'][0]
    flow.fetch_token(code=code)
    return flow.credentials

scopes = ['https://www.googleapis.com/auth/drive.file']
flow = InstalledAppFlow.from_client_secrets_file(secrets_file, scopes)
credentials = run_console_hack(flow)

我们还可以要求用户直接传回code查询字符串参数,但这很可能会使人感到困惑,而且容易出错。
使用1作为端口号意味着请求肯定会失败,而不是可能命中某个碰巧在该端口上运行的服务。(例如,Chrome将在ERR_UNSAFE_PORT下失败,甚至不尝试连接)

vd8tlhqk

vd8tlhqk6#

我已经修复了这个问题与重新创建我的应用程序在谷歌控制台。我认为问题是与redirect_url。我有这个问题时,我正在使用'Android'类型的应用程序在谷歌控制台(在这种情况下,你不能配置重定向网址)。在我的Android应用程序,我使用谷歌认证与WebView,所以最好的选择在这里使用使用'Web'类型为您的应用程序在谷歌控制台。

xjreopfe

xjreopfe7#

**“Hello world”**表示此错误:

生成验证URL

https://github.com/googleapis/google-api-nodejs-client#generating-an-authentication-url

const {google} = require('googleapis');

const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// generate a url that asks permissions for Blogger and Google Calendar scopes
const scopes = [
  'https://www.googleapis.com/auth/blogger',
  'https://www.googleapis.com/auth/calendar'
];

const url = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',

  // If you only need one scope you can pass it as a string
  scope: scopes
});

如果出现问题,第一步是再次重新检查google.auth.OAuth2函数的三个值。

第1页,共2页

Google APIs console下的存储值进行比较:

  1. YOUR_CLIENT_ID

  2. YOUR_CLIENT_SECRET

  3. YOUR_REDIRECT_URL-

    例如,登录名为

第2个,共2个(环境变量)

很多时候,值存储在.env中。因此,请重新检查env和文件下的输出-例如index.ts(甚至使用console.log)。
.env


# Google Sign-In (OAuth)

G_CLIENT_ID=some_id_1234
G_CLIENT_SECRET=some_secret_1234
PUBLIC_URL=http://localhost:3000

index

const auth = new google.auth.OAuth2(
  process.env.G_CLIENT_ID,
  process.env.G_CLIENT_SECRET,
  `${process.env.PUBLIC_URL}/login`
);

总和:

这样的事情是行不通的

const oauth2Client = new google.auth.OAuth2(
  "no_such_id",
  "no_such_secret",
  "http://localhost:3000/i_forgot_to_Authorised_this_url"
);
6jygbczu

6jygbczu8#

在我的情况下,必须更新插件。通过运行以下命令-

bundle exec fastlane update_plugins

使用此重定向URI将正确创建为

https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&client_id=563584335869-fgrhgmd47bqnekij5i8b5pr03ho849e6.apps.googleusercontent.com&include_granted_scopes=true&redirect_uri=http://localhost:8081&response_type=code&scope=https://www.googleapis.com/auth/cloud-platform&state=2ce8a59b2d403f3a89fa635402bfc5c4
gmol1639

gmol16399#

steps.oauth.v2.invalid_request 400这个错误名用于多种不同类型的错误,通常用于请求中发送的参数丢失或不正确。如果设置为false,则使用fault变量(如下所述)来检索有关错误的详细信息,如错误名和原因。

  • 生成访问令牌生成授权代码
  • 生成访问令牌隐式授予
  • 刷新访问令牌

Google Oauth Policy

相关问题