K
KindeNanaGaisie

Integrating Convex with Kinde

Hey, I am trying to implement custom authentication with convex. I have done as their documentation says on implements custom authentication. That being said using the useKindeBrowserClient hook to access the isAuthenticated auth data inside the ConvexProviderWithKinde when signed in returns false. I tried logging to the console the auth data in a different component and got the expected result. The attached files show how I am implementing the custom auth. I would appreciate any explanation of why this happens and possible ways to resolve this issue.
O
onderay42d ago
To address the issue you're encountering with the useKindeBrowserClient hook returning false for isAuthenticated within the ConvexProviderWithKinde but working as expected in a different component, let's consider a few potential causes and solutions: Timing and React's Rendering Cycle: The useKindeBrowserClient hook might be called at a point in the component's lifecycle where the authentication status has not been fully resolved yet. This could be particularly true if there's a delay in fetching or verifying the authentication status from Kinde's servers. Solution: Ensure that any component relying on the isAuthenticated status from useKindeBrowserClient properly handles loading states. This might involve conditional rendering based on the isLoading state or implementing a retry mechanism for checking the isAuthenticated status after a brief delay. Scope and Propagation of Context: If ConvexProviderWithKinde is a context provider that wraps around the useKindeBrowserClient hook, there might be an issue with how the authentication context is being propagated down to child components. Solution: Verify that the ConvexProviderWithKinde component correctly integrates with Kinde's authentication context and that there are no issues with context shadowing or improper context usage. It might be helpful to use React Developer Tools to inspect the component hierarchy and context values. Custom Implementation Specifics: Since you're implementing custom authentication with Convex and integrating it with Kinde, there might be specific nuances or requirements in the integration that are not fully addressed. Solution: Review the implementation details of both the Convex and Kinde integration, focusing on how authentication tokens are managed, refreshed, and passed between the two systems. Ensure that the getToken method from your UseKindeAuth type is correctly implemented and that it properly interacts with Kinde's authentication flow. Debugging and Further Investigation: Since you mentioned that logging the auth data in a different component yields the expected result, it suggests that the issue might be localized to the specific context or component structure you're using with Convex. Solution: Implement additional logging at various points in the authentication flow to pinpoint where the discrepancy occurs. This might involve logging the output of useKindeBrowserClient at different component levels or within different hooks to identify where the isAuthenticated value diverges from expectations. Without access to the full codebase or specific implementation details, these suggestions are based on common patterns and potential issues in React authentication flows. If your issue persists, the team can take a look, but we don't have any previous experience with Convex.
D
/dev/null24d ago
Hey @NanaGaisie have you figured out a possible solution ?
N
NanaGaisie24d ago
@/dev/null access the token with kindeBrowserClient in the useAuth. Also wrap all components that needs authentication with convex's Authenticated component. I suggest grouping all components that need authentication and having a common layout file which handles loading, and authentication states using convex's provided components.
D
/dev/null24d ago
I have managed to re-use your code:
"use client";
import useStoreUserEffect from "@/lib/useStoreUserEffect";
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
import { ConvexProviderWithAuth, ConvexReactClient } from "convex/react";
import { useCallback, useMemo } from "react";

type UseKindeAuth = () => {
isLoading: boolean | null;
isAuthenticated: boolean | null;
getToken: () => string | null;
};

function useUseAuthFromKinde(useAuth: UseKindeAuth) {
return useMemo(
() =>
function useAuthFromKinde() {
const { isLoading, isAuthenticated, getToken } = useAuth();
const fetchAccessToken = useCallback(
async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => {
try {
return await getToken();
} catch (error) {
return null;
}
},
[getToken]
);
return useMemo(
() => ({
isLoading: isLoading ?? false,
isAuthenticated: isAuthenticated ?? false,
fetchAccessToken,
}),
[isLoading, isAuthenticated, fetchAccessToken]
);
},
[useAuth]
);
}

const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

const useCurrentUser = () => {
const { isLoading, isAuthenticated, getToken } = useKindeBrowserClient();

console.log("isAuthenticated", isAuthenticated);

return { isLoading, isAuthenticated, getToken };
};

export function ConvexClientProvider({
children,
}: {
children: React.ReactNode;
}) {
{
const useAuthFromKinde = useUseAuthFromKinde(useCurrentUser);

// useStoreUserEffect();
return (
<ConvexProviderWithAuth client={convex} useAuth={useAuthFromKinde}>
{children}
</ConvexProviderWithAuth>
);
}
}
"use client";
import useStoreUserEffect from "@/lib/useStoreUserEffect";
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
import { ConvexProviderWithAuth, ConvexReactClient } from "convex/react";
import { useCallback, useMemo } from "react";

type UseKindeAuth = () => {
isLoading: boolean | null;
isAuthenticated: boolean | null;
getToken: () => string | null;
};

function useUseAuthFromKinde(useAuth: UseKindeAuth) {
return useMemo(
() =>
function useAuthFromKinde() {
const { isLoading, isAuthenticated, getToken } = useAuth();
const fetchAccessToken = useCallback(
async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => {
try {
return await getToken();
} catch (error) {
return null;
}
},
[getToken]
);
return useMemo(
() => ({
isLoading: isLoading ?? false,
isAuthenticated: isAuthenticated ?? false,
fetchAccessToken,
}),
[isLoading, isAuthenticated, fetchAccessToken]
);
},
[useAuth]
);
}

const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

const useCurrentUser = () => {
const { isLoading, isAuthenticated, getToken } = useKindeBrowserClient();

console.log("isAuthenticated", isAuthenticated);

return { isLoading, isAuthenticated, getToken };
};

export function ConvexClientProvider({
children,
}: {
children: React.ReactNode;
}) {
{
const useAuthFromKinde = useUseAuthFromKinde(useCurrentUser);

// useStoreUserEffect();
return (
<ConvexProviderWithAuth client={convex} useAuth={useAuthFromKinde}>
{children}
</ConvexProviderWithAuth>
);
}
}
Having everything needed for the authentication on a single file. Then using like this on my layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>
<ConvexClientProvider>{children}</ConvexClientProvider>
</body>
</html>
);
}
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>
<ConvexClientProvider>{children}</ConvexClientProvider>
</body>
</html>
);
}
I tried the two components from kinde, the register seems to be working fine, but the <LoginLink> is not working. I tried to then login through the register but the state is just false when logging the authentication bool state you've inserted. page.tsx ⬇️
mport { LoginLink, RegisterLink } from "@kinde-oss/kinde-auth-nextjs";

export default function Home() {
return (
<main className="">
<LoginLink>Login</LoginLink>
<RegisterLink>Register</RegisterLink>
</main>
);
}
mport { LoginLink, RegisterLink } from "@kinde-oss/kinde-auth-nextjs";

export default function Home() {
return (
<main className="">
<LoginLink>Login</LoginLink>
<RegisterLink>Register</RegisterLink>
</main>
);
}
N
NanaGaisie23d ago
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
import { useCallback, useMemo } from "react";

interface UseAuthReturn {
isLoading: boolean;
isAuthenticated: boolean;
fetchAccessToken: (args: {
forceRefreshToken: boolean;
}) => Promise<string | null>;
}

export function useAuthFromKinde(): UseAuthReturn {
const { isLoading, isAuthenticated, getAccessTokenRaw, accessToken } =
useKindeBrowserClient();
const fetchAccessToken = useCallback(
async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => {
if (forceRefreshToken) {
try {
const response = await getAccessTokenRaw();
// Returns the token as string
return response;
} catch (error) {
return null;
}
}
// Add this line to ensure the function always returns a string or null
return null;
},
[accessToken],
);

return useMemo(
() => ({
isLoading: isLoading ?? false,
isAuthenticated: isAuthenticated ?? false,
fetchAccessToken,
}),
[isLoading, isAuthenticated, fetchAccessToken],
);
}
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
import { useCallback, useMemo } from "react";

interface UseAuthReturn {
isLoading: boolean;
isAuthenticated: boolean;
fetchAccessToken: (args: {
forceRefreshToken: boolean;
}) => Promise<string | null>;
}

export function useAuthFromKinde(): UseAuthReturn {
const { isLoading, isAuthenticated, getAccessTokenRaw, accessToken } =
useKindeBrowserClient();
const fetchAccessToken = useCallback(
async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => {
if (forceRefreshToken) {
try {
const response = await getAccessTokenRaw();
// Returns the token as string
return response;
} catch (error) {
return null;
}
}
// Add this line to ensure the function always returns a string or null
return null;
},
[accessToken],
);

return useMemo(
() => ({
isLoading: isLoading ?? false,
isAuthenticated: isAuthenticated ?? false,
fetchAccessToken,
}),
[isLoading, isAuthenticated, fetchAccessToken],
);
}
This is my useAuth function. I tried using getToken to access the token. This does not work as the values returned does not have the AUD. Using the getAccesToken returns the AUD. Also the dependency array of the use Callback should not be set to the function to avoid re-rendering of the component. Use the accessToken instead from the useKindeBrowserClient. Also wrap all children that require authentication in the Authenticated provider from convex/react.
Want results from more Discord servers?
Add your server
More Posts
Empty permissions and no roles in jwt tokens.i am using Kinde for login in react/vite ( that works) and want to us eit for authorization in my flCreating users via Kinde APIHi there! Super new to Kinde and web development in general so apologies for my lack of knowledge inlogin front and backend with same tokenHi, I'm new using kinde and I'm surprised, it's great. My architecture is nuxt3 front and feathers Machine to Machine Account & Custom DomainWhen making an api call with a machine to machine account, it's working with our {businesname}.kindeerror: getuser is not a functionI get the error: ```tsx Header.tsx:18 Uncaught (in promise) TypeError: getUser is not a function More frequent 504 errorsHi. I have heard a more frequent complaint of "504 Gateway Timeout" errors (last one was ~9 hours Next.js - Middleware for Kinde & Redirect to login pageHi, I'm coming from a Kinde competitor, I love Kinde. It has many more advantage for me also how it <LoginLink> / <RegisterLink> causes: "Error: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext)"CODE CAUSES ERROR: ```js import { LoginLink, RegisterLink } from "@kinde-oss/kinde-auth-nextjs"; //redirectIs it possible to support dynamic post-login redirects instead of changing the `KINDE_POST_LOGIN_REDKindeSDKError2: Attempting to commit invalid id_token token "undefined" to memoryhi, i am running into this error when running into production and am not sure why because it doesn'tAny new competitions ?Updates on new competitionscustom domaini have configured my subdomain 'https://accounts.coachbots.com/' but it shows privacy error. my otheCan I describe external id usingI want to store additional data and want to access it like a subscription expiring date, and some meIntegrating with React, Vite, URQLhey folks, im trying to intergrate Kinde auth with urql, and I'm running into some issues. first oOrganization branding controlWith Auth0, my Applications have a Logo URL (which would be handled in Organizations it seems with KIs there any hook in React to update user profile (email/firstname/lasname - custom properties)?.Proper use of Organizations as opposed to ApplicationsWe are a multi-tenant SaaS product. Each tenant gets their own Application (client id, secret). In oWe can't find your accountCan this message be skipped, I have disabled "Ask for user first name and last name" so if the user