JubilantJam
JubilantJam5mo ago

Convex-auth with solid or other non-react frameworks

Is there a reccomended way to set up convex-auth for frameworks other than react? I've gotten pretty far with solid js by just calling the signIn/signOut actions from convexAuth() from @convex-dev/auth/server. I can successfully retrieve the auth token but I can't seem to get convex to recognize the user as signed in.
1 Reply
JubilantJam
JubilantJamOP5mo ago
I have it working for the most part. I manually store the token in localStorage and then get it out on mount:
// Root of my Solid Start app
const convex = new ConvexClient(import.meta.env.VITE_CONVEX_URL);

onMount(() => {
if (convex) {
convex.setAuth(async () =>
localStorage.getItem(import.meta.env.VITE_CONVEX_AUTH_TOKEN),
);
}
});
// Root of my Solid Start app
const convex = new ConvexClient(import.meta.env.VITE_CONVEX_URL);

onMount(() => {
if (convex) {
convex.setAuth(async () =>
localStorage.getItem(import.meta.env.VITE_CONVEX_AUTH_TOKEN),
);
}
});
I think the final version of this probably looks like including refresh logic with the refresh token inside the function you pass to setAuth, but this will do for development This seems to work pretty well:
const convex = new ConvexClient(CONVEX_URL);

onMount(() => {
if (convex) {
convex.setAuth(
async ({ forceRefreshToken }) => {
const token = localStorage.getItem(TOKEN_KEY);
const lastRefresh = localStorage.getItem('lastTokenRefresh');
let refreshedRecently = false;

if (lastRefresh) {
const timeSinceRefresh = Date.now() - parseInt(lastRefresh);
refreshedRecently = timeSinceRefresh < 1000 * 60 * 10; // 10 minutes
}

console.log('refreshedRecently:', refreshedRecently);
console.log('forceRefreshToken:', forceRefreshToken);

if ((forceRefreshToken && !refreshedRecently) || !token) {
const newToken = await handleRefreshToken();

localStorage.setItem('lastTokenRefresh', Date.now().toString());

return newToken;
} else {
return token;
}
},
(isAuthenticated) => {
console.log('authenticated:', isAuthenticated);
},
);
}
});
const convex = new ConvexClient(CONVEX_URL);

onMount(() => {
if (convex) {
convex.setAuth(
async ({ forceRefreshToken }) => {
const token = localStorage.getItem(TOKEN_KEY);
const lastRefresh = localStorage.getItem('lastTokenRefresh');
let refreshedRecently = false;

if (lastRefresh) {
const timeSinceRefresh = Date.now() - parseInt(lastRefresh);
refreshedRecently = timeSinceRefresh < 1000 * 60 * 10; // 10 minutes
}

console.log('refreshedRecently:', refreshedRecently);
console.log('forceRefreshToken:', forceRefreshToken);

if ((forceRefreshToken && !refreshedRecently) || !token) {
const newToken = await handleRefreshToken();

localStorage.setItem('lastTokenRefresh', Date.now().toString());

return newToken;
} else {
return token;
}
},
(isAuthenticated) => {
console.log('authenticated:', isAuthenticated);
},
);
}
});
handleRefreshToken simply gets the current refresh token from local storage and hits the convex-auth signIn action with a the refreshToken as the only parameter. You can do this with the browser client or from your backend as long as the new tokens end up in your front-end's local storage. If you aren't using react and thus don't get to use all the convex-auth helper components, you may want to hit the action from you backend so that you can put the tokens in secure, same-site, http-only cookies as well to use for protected routes. (So in a single response you set the cookies in the headers AND send the tokens down in the JSON body so the frontend can put in localStorage)

Did you find this page helpful?