tomasvotava / fastapi-sso

FastAPI plugin to enable SSO to most common providers (such as Facebook login, Google login and login via Microsoft Office 365 Account)
https://tomasvotava.github.io/fastapi-sso/
MIT License
317 stars 50 forks source link

303 Error while using with react #175

Open Zaeem6100 opened 3 months ago

Zaeem6100 commented 3 months ago

With the browser direct backend URL hit it works fine but when I do button trigger call with the react app it gives me an error

Backend Code `CLIENT_ID = os.environ["CLIENT_ID"] CLIENT_SECRET = os.environ["CLIENT_SECRET"] REDIRECT_URI = "http://localhost:5000/api/v1/auth/callback"

os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

auth_client = AuthClient( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, redirect_url=REDIRECT_URI ) restli_client = RestliClient()

sso = LinkedInSSO( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, redirect_uri=REDIRECT_URI, allow_insecure_http=True )

@router.get("/login", tags=['LinkedIn SSO']) async def login(): with sso: return await sso.get_login_redirect()

@router.get("/callback") async def oauth(code: str, request: Request): try: if code: user = await sso.verify_and_process(request) userDao = UserDAO() token_response = auth_client.exchange_auth_code_for_access_token(code) access_token = token_response.access_token user = User( lastName=user.last_name, firstName=user.first_name, linkedin_id=user.id, email=user.email, access_token=access_token ) print(f"Auth User {user}") userDao.update_or_insert_user(user) frontend_url = f"http://localhost:5173/auth/callback#id={user.linkedin_id}" return RedirectResponse(url=frontend_url, status_code=303) except Exception as e: raise HTTPException(status_code=400, detail=str(e))`

tomasvotava commented 3 months ago

Hey there, could you please tell me more about the actual error? Could you copy what you see in devtools console in your browser when that happens? My guess is React does not expect the 303 redirect, maybe 307 would work, but I'd need to see more to know :)

Zaeem6100 commented 3 months ago

here is my frontend code

` import {Button} from "@/components/ui/button" import {SVGProps} from "react" import {JSX} from "react/jsx-runtime" import axios from "axios"

export default function LoginWithLinkedIn() { const handleLogin = () => { axios.get('http://localhost:5000/api/v1/auth/login') .then(response => { console.log('Login Success:', response); if (response.data) { window.location.href = response.data; } }) .catch(error => { console.error('Login Error:', error); }); };

return (
    <div className="flex h-screen w-full items-center justify-center bg-white px-4">
        <div className="mx-auto max-w-md space-y-6 rounded-lg bg-white p-8 dark:bg-gray-900">
            <div className="space-y-2 text-center">
                <h1 className="text-3xl font-bold">Connect your LinkedIn</h1>
                <p className="text-gray-500 dark:text-gray-400">
                    To get started, please connect your LinkedIn account. This will help us personalize your
                    experience and
                    provide you with relevant recommendations.
                </p>
            </div>
            <Button className="w-full" onClick={handleLogin}>
                <LinkedinIcon className="mr-2 h-5 w-5"/>
                Connect LinkedIn
            </Button>
        </div>
    </div>
)

}

function LinkedinIcon(props: JSX.IntrinsicAttributes & SVGProps) { return ( <svg {...props} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"

) } `

here is the error Console log image

Backend image

tomasvotava commented 3 months ago

Oh, I see, your axios.get(<login url>) does not make any sense in this case. You need to redirect the user to the page and handle the redirection back after the callback. If you replace your axios.get('http://localhost:5000/api/v1/auth/login') with e.g. window.location.replace('http://localhost:5000/api/v1/auth/login') you should get the login to work. But that's just the first step, because you need to redirect the user back to where they were in your callback handler back in Python.