Google OAuth2.0 – 不经意地重定向到 http

huangapple go评论136阅读模式
英文:

Google OAuth2.0 - Unintended redirecting to http

问题

我正在为我的FARM堆栈应用程序设置Google OAuth。

我的问题是:
当我在本地运行应用程序时,我的流程和代码是有效的。
但是在生产环境中不起作用(因为如果我的OAuth应用程序设置为生产模式,Google不允许我输入“http”方案的重定向URL)。
我已经满足了所有要求,例如客户端ID、重定向URI。

以下是我遵循的步骤:

1- 为Web应用程序创建了客户端ID。
2- 添加所需的重定向URI。
3- 在FastAPI中,我有以下代码:

# config["CLIENT_URL"]等于我的React应用程序的URL。
@router.get('/google_cb')  # 1
async def login(request: Request):
    redirect_uri = request.url_for('google')
    return await oauth.google.authorize_redirect(request, redirect_uri)


@router.get("/google", name="google")  # 2
async def google_oauth(request: Request):
    try:
        access_token = await oauth.google.authorize_access_token(request)
        user = user_service.find_one(
            {"email": access_token['userinfo']['email'], "authentication_method": AuthenticationMethod.GOOGLE})
        if user:
            access_token_expires = timedelta(minutes=config["Auth"]["token_expiry"])
            access_token = create_access_token(
                data={"sub": user.id, "scopes": []},
                expires_delta=access_token_expires,
            )
            return RedirectResponse(url=f'{config["CLIENT_URL"]}/oauthcb/' + access_token)
        invite = invites_repository.find_one({"email": access_token['userinfo']['email'], "status": "Pending"})
        if not invite:
            raise HTTPException(status_code=404, detail="Invite not found")
        created_user = user_service create_user(
            {"email": invite["email"], "hashed_password": "google_auth",
             "tenant_id": invite["tenant_id"], "disabled": False, "first_name": access_token['userinfo']['given_name'],
             "last_name": access_token['userinfo']['family_name'], "is_admin": False, "fireflies_id": None,
             "authentication_method": "Google", "external_auth_data": access_token})
        access_token_expires = timedelta(minutes=config["Auth"]["token_expiry"])
        access_token = create_access_token(
            data={"sub": str(created_user.inserted_id), "scopes": []},
            expires_delta=access_token_expires,
        )
        invites_repository.delete({"_id": invite["_id"]})
        return RedirectResponse(url=f'{config["CLIENT_URL"]}/oauthcb/' + access_token)
    except OAuthError as e:
        print(e)
        return RedirectResponse(url=f'{config["CLIENT_URL"]}')

4- 在React中,我有以下代码:

process.env.REACT_APP_API_URL设置为https://my.api.url

<Button
    icon={<GoogleOutlined />}
    onClick={() => {
        window.location.replace(
            `${process.env.REACT_APP_API_URL}/oauth/google_cb`
        );
    }}
>
    Login with Google
</Button>

5- 流程:用户在React应用程序中按下Google登录按钮,用户在后端命中https://my.api.url/google_cb端点。后端将用户重定向到Google提供的页面,以输入其电子邮件和密码。登录后,Google应该将用户重定向到https://my.api.url/google端点,我在这里进行处理。

问题是:尽管我将用户从React重定向到https://my.api.endpoint/google_cb
但我收到“redirect_url_mismatch”错误,并且错误中说“redirect_url=http://my.api.endpoint/google_cb”
这导致了我的问题。我很确定这是因为我将我的OAuth应用程序从Google控制台切换到“测试”模式而不是“生产”模式时才会出现的。

在生产模式下,Google不允许我输入http URL。他们只允许我输入https。

但我非常确定我将用户重定向到https而不是http。

我想知道是否有人在以前遇到过类似的问题。

英文:

I'm trying to setup a Google OAuth for my FARM stack app.

My problem is:
My flow and code is working when I'm running the app in my local.
But It's not working in production. (Because Google doesn't allow me to enter a redirect url in "http" scheme if my OAuth app is set to Production mode.)
I have all the requirements satisfied, e.g ClientID, Redirect URI's.

Here's the steps I follow:

1- Created ClientId for Web Application.
2- Added the required redirect URIs.
3- In FastAPI I have this code:

# config[&quot;CLIENT_URL&quot;] equals to my React App&#39;s url.
@router.get(&#39;/google_cb&#39;)  # 1
async def login(request: Request):
    redirect_uri = request.url_for(&#39;google&#39;)
    return await oauth.google.authorize_redirect(request, redirect_uri)


@router.get(&quot;/google&quot;, name=&quot;google&quot;)  # 2
async def google_oauth(request: Request):
    try:
        access_token = await oauth.google.authorize_access_token(request)
        user = user_service.find_one(
            {&quot;email&quot;: access_token[&#39;userinfo&#39;][&#39;email&#39;], &quot;authentication_method&quot;: AuthenticationMethod.GOOGLE})
        if user:
            access_token_expires = timedelta(minutes=config[&quot;Auth&quot;][&quot;token_expiry&quot;])
            access_token = create_access_token(
                data={&quot;sub&quot;: user.id, &quot;scopes&quot;: []},
                expires_delta=access_token_expires,
            )
            return RedirectResponse(url=f&#39;{config[&quot;CLIENT_URL&quot;]}/oauthcb/&#39; + access_token)
        invite = invites_repository.find_one({&quot;email&quot;: access_token[&#39;userinfo&#39;][&#39;email&#39;], &quot;status&quot;: &quot;Pending&quot;})
        if not invite:
            raise HTTPException(status_code=404, detail=&quot;Invite not found&quot;)
        created_user = user_service.create_user(
            {&quot;email&quot;: invite[&quot;email&quot;], &quot;hashed_password&quot;: &quot;google_auth&quot;,
             &quot;tenant_id&quot;: invite[&quot;tenant_id&quot;], &quot;disabled&quot;: False, &quot;first_name&quot;: access_token[&#39;userinfo&#39;][&#39;given_name&#39;],
             &quot;last_name&quot;: access_token[&#39;userinfo&#39;][&#39;family_name&#39;], &quot;is_admin&quot;: False, &quot;fireflies_id&quot;: None,
             &quot;authentication_method&quot;: &quot;Google&quot;, &quot;external_auth_data&quot;: access_token})
        access_token_expires = timedelta(minutes=config[&quot;Auth&quot;][&quot;token_expiry&quot;])
        access_token = create_access_token(
            data={&quot;sub&quot;: str(created_user.inserted_id), &quot;scopes&quot;: []},
            expires_delta=access_token_expires,
        )
        invites_repository.delete({&quot;_id&quot;: invite[&quot;_id&quot;]})
        return RedirectResponse(url=f&#39;{config[&quot;CLIENT_URL&quot;]}/oauthcb/&#39; + access_token)
    except OAuthError as e:
        print(e)
        return RedirectResponse(url=f&#39;{config[&quot;CLIENT_URL&quot;]}&#39;)

4- In React I have this code:

process.env.REACT_APP_API_URL is set to https://my.api.url
&lt;Button
            icon={&lt;GoogleOutlined /&gt;}
            onClick={() =&gt; {
              window.location.replace(
                `${process.env.REACT_APP_API_URL}/oauth/google_cb`
              );
            }}
          &gt;
            Login with Google
          &lt;/Button&gt;

5- Flow: User presses Login With Google button in React App, user hits the https://my.api.url/google_cb endpoint in the backend. The backend redirects the user to the page that google provides to enter their email and password. After they log in, google should redirect the user to https://my.api.url/google endpoint and I do my process here.

Problem is: Although I'm redirecting the user from React to the https://my.api.endpoint/google_cb
I'm getting an error "redirect_url_mismatch", and in the error it says "redirect_url=http://my.api.endpoint/google_cb"
And this causes my problem. I'm sure about this because I swithced the mode for my OAuth App from Google Console to "Test" from "Production" and It worked.

In production mode Google doesn't allow me to enter http url. They just allow me to enter https.

But I'm pretty pretty sure that I'm redirecting the user to https instead of http.

I wonder if anyone faced with the same issue before.

答案1

得分: 0

问题已解决,问题出在request.url_for函数返回的URL是"http"而不是"https"。

我更新了我的代码如下:

async def login(request: Request):
    redirect_uri = request.url_for('google')
    if request.base_url.hostname == 'localhost': 
# 我考虑到本地主机用于测试目的,你可能没有这个。
        redirect_uri = redirect_uri.replace('https', 'http')
    else:
        redirect_uri = redirect_uri.replace('http', 'https')
    return await oauth.google.authorize_redirect(request, redirect_uri)

确保你的后端重定向到正确的URL!

英文:

Solved, the issue is request.url_for function returns the url as "http" instead of "https".

Updated my code as:

async def login(request: Request):
    redirect_uri = request.url_for(&#39;google&#39;)
    if request.base_url.hostname == &#39;localhost&#39;: 
# I consider about localhost for testing purposes, you may not have this.
        redirect_uri = redirect_uri.replace(&#39;https&#39;, &#39;http&#39;)
    else:
        redirect_uri = redirect_uri.replace(&#39;http&#39;, &#39;https&#39;)
    return await oauth.google.authorize_redirect(request, redirect_uri)

Make sure your backend redirects to the correct url!

huangapple
  • 本文由 发表于 2023年3月10日 00:36:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75687525.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定