kinde-oss / kinde-auth-react

Kinde React SDK for frontend authentication flows
https://kinde.com/docs/developer-tools/react-sdk/
MIT License
50 stars 11 forks source link

Bug: (I attempted to deploy the React Kinde app to Vercel) #54

Open thesushilsharma opened 1 month ago

thesushilsharma commented 1 month ago

Prerequisites

Describe the issue

After entering the OTP during the registration. It is not redirecting to the dashboard or cannot log in with the same credentials.

image image

I check in the Discord community.

But this all works in localhost.

Library URL

https://github.com/kinde-oss/kinde-auth-react

Library version

@kinde-oss/kinde-auth-react": "^4.0.1"

Operating system(s)

Windows

Operating system version(s)

Win 10

Further environment details

No response

Reproducible test case URL

No response

Additional information

No response

peterphanouvong commented 1 month ago

Hey @thesushilsharma sorry you're having this issue - deployment can be tricky sometimes. Would you be able to share your .env variables that you have in prod?

VITE_KINDE_DOMAIN=https://peteswah.kinde.com
VITE_KINDE_REDIRECT_URL=http://localhost:3000
VITE_KINDE_LOGOUT_URL=http://localhost:3000
thesushilsharma commented 1 month ago
clientId={import.meta.env.VITE_KINDE_CLIENT_ID}
domain="https://basebrett.kinde.com"
logoutUri={window.location.origin}
redirectUri={window.location.origin}
peterphanouvong commented 1 month ago

Thanks @thesushilsharma - you said that it's not redirecting to the dashboard - where is it redirecting to instead?

thesushilsharma commented 1 month ago

It redirects to the home page. If I attempt to log in, it doesn't work and redirects me to the homepage.

Website Link

peterphanouvong commented 1 month ago

Hey @thesushilsharma, I managed to recreate the issue and solve it with a slight tweak to your handleRedirectCallback to look like this:

const handleRedirectCallback = (user, appState) => {
  console.log({ user, appState });
  if (appState?.redirectTo) {
    window.location = appState.redirectTo;
  } else {
    window.location = "/";
  }
};

We believe that .href may have caused js issues with navigation & prevented our JS from running and broke auth :(

Hopefully this fixes it for you!

thesushilsharma commented 1 month ago

I attempted to work without using .href, but unfortunately, it resulted in the same unauthenticated issue.

If I remove the redirect function, everything works fine. I can log in and view the dashboard without any issues.

However, while localhost works perfectly, something is missing with the redirect, protected route, and dashboard after deploying to Vercel.

src/views/ProtectedRoute.jsx

import React from 'react';
import { useKindeAuth } from '@kinde-oss/kinde-auth-react';
import { Outlet } from 'react-router-dom';

const ProtectedRoute = () => {
  const { isLoading, isAuthenticated, login } = useKindeAuth();

  console.log('ProtectedRoute:', { isLoading, isAuthenticated });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!isLoading && !isAuthenticated) {
    return (
      <div>
        <h1 className="text-3xl font-medium">Not authenticated</h1>
        <button
          onClick={() => login()}
          className="bg-zinc-900 text-white px-3 py-2 rounded"
        >
          Login
        </button>
      </div>
    );
  }

  if (!isLoading && isAuthenticated) {
    return <Outlet />;
  }

  return null;
};

export default ProtectedRoute;

src/views/Dashboard.jsx

import React, { useEffect } from 'react';
import { useKindeAuth } from "@kinde-oss/kinde-auth-react";
import { Link } from 'react-router-dom';

const Dashboard = () => {
    const { isLoading, isAuthenticated, user, logout, getToken } = useKindeAuth();

    const fetchData = async () => {
        try {
            if (isAuthenticated) {
                console.log(JSON.stringify(user, null, 2));
                const accessToken = await getToken();
                console.log(`Bearer ${accessToken}`);
            }
        } catch (err) {
            console.error(err);
        }
    };

    useEffect(() => { fetchData() },)

    return (
        <>
            {!isLoading && isAuthenticated && (
                <div className="space-y-4">
                    <div className="flex flex-col items-center">
                        <img src={user?.picture} alt="user" className="rounded-full h-24 w-24 object-cover mb-2" />
                        <p className="text-lg font-semibold">Welcome, {user?.given_name}!</p>
                        <p className="text-gray-600">{user?.email}</p>
                    </div>

                    <div className="grid grid-cols-2 gap-4 mt-4">
                        <button type="button">Ledger</button>
                        <Link to="KYC"><button type="button">Buy </button></Link>
                    </div>

                    <button
                        onClick={logout}>
                        Log out
                    </button>
                </div>
            )}

        </>
    );
};

export default Dashboard;

src/components/Auth.jsx

import React from 'react'
import { useNavigate } from 'react-router-dom';
import { useKindeAuth } from "@kinde-oss/kinde-auth-react";
export default function Auth() {
    const { login, register, isLoading, isAuthenticated } =
        useKindeAuth();
    const navigate = useNavigate();
    React.useEffect(() => {
        if (isAuthenticated) {
            navigate('/dashboard');
        }
    }, [isAuthenticated, navigate]);

    const handleLogin = () => {
        login({
            app_state: { redirectTo: '/dashboard' }
        });

    };

    const handleRegister = () => {
        register({
            app_state: { redirectTo: '/dashboard' }
        });

    };

    return (
        <>
            {isLoading && (
                <p className="text-center text-gray-500 dark:text-gray-400">Loading...</p>
            )}

            {!isLoading && !isAuthenticated && (
                <div>
                    <button
                        onClick={handleRegister} type="button">
                        Register
                    </button>
                    <button
                        onClick={handleLogin} type="button">
                        Log In
                    </button>
                </div>
            )}

        </>
    )
}

src/main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import App from './App.jsx'
import './index.css'
import NotFoundPage from './views/NotFoundPage';
import Dashboard from './views/Dashboard';
import ProtectedRoute from './views/ProtectedRoute';
import Auth from './components/Auth';

import { KindeProvider } from "@kinde-oss/kinde-auth-react";

const router = createBrowserRouter([
  {
    path: '/',
    element: <App />,
    errorElement: <NotFoundPage />,
  },
  {
    path: '/Auth',
    element: <Auth />,
  },
  {
    path: '/dashboard',
    element: <ProtectedRoute />,
    children: [
      {
        index: true,
        element: <Dashboard />,
      },
    ],
  },
]);

const handleRedirectCallback = (user, appState) => {
  console.log({ user, appState });
  if (appState?.redirectTo) {
    window.location = appState.redirectTo;
  } else {
    window.location = "/";
  }
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <KindeProvider
      clientId={import.meta.env.VITE_KINDE_CLIENT_ID}
      domain="https://basebrett.kinde.com"
      logoutUri={window.location.origin}
      redirectUri={window.location.origin}
      onRedirectCallback={handleRedirectCallback}
    >
      <RouterProvider router={router} />
    </KindeProvider>
  </React.StrictMode>,
)
peterphanouvong commented 1 month ago

Hey @thesushilsharma sorry you're still having issues :(

We deployed a version of the github repo you sent us here https://basedbrett-two.vercel.app/ which should have working authentication.

The code for that is here: https://github.com/peterphanouvong/basedbrett

thesushilsharma commented 1 month ago

Able to redirect to the dashboard after setting isDangerouslyUseLocalStorage={true}

Let me know if there is a better solution.