Convex-Gate: Better Auth Adapter for Convex

0.1.3 · active · verified Wed Apr 22

Convex-Gate is an alpha-stage package designed to integrate the Better Auth authentication system with Convex applications. It provides an isolated authentication data store within a Convex component, separating auth concerns from application data. Key features include a dedicated hot-path for rapid session resolution, server-side JWT caching with configurable TTL, client-side token expiry awareness, and support for static JWKS. It also offers React bindings via `ConvexBetterAuthProvider` and is compatible with all Better Auth plugins (2FA, SSO, organizations, passkeys). The current version is 0.1.3, and due to its alpha status, APIs are subject to change. Release cadence is currently irregular as it's under active development.

Common errors

Warnings

Install

Imports

Quickstart

This code sets up the client-side authentication for a React application using Convex-Gate. It initializes the Better Auth client with Convex-Gate plugins, wraps the application with `ConvexBetterAuthProvider`, and demonstrates conditional rendering based on authentication status with sign-in and sign-out functionality.

import { ConvexReactClient } from "convex/react";
import { ConvexBetterAuthProvider } from "convex-gate/react";
import { authClient } from "./lib/auth-client";
import { createAuthClient } from "better-auth/react";
import { convexClient, crossDomainClient } from "convex-gate/client/plugins";
import React from 'react';
import ReactDOM from 'react-dom/client';

// --- Client Auth Setup (src/lib/auth-client.ts) ---
export const authClient = createAuthClient({
  baseURL: import.meta.env.VITE_CONVEX_SITE_URL ?? '', // Use empty string if undefined for SSR compatibility
  plugins: [
    crossDomainClient(),
    convexClient(),
  ],
});

// --- Main App Component (src/App.tsx) ---
import { Authenticated, Unauthenticated } from "convex/react";

function App() {
  return (
    <>
      <h1>Convex-Gate Demo</h1>
      <Authenticated>
        <p>You are authenticated!</p>
        <button onClick={() => authClient.signOut()}>Sign Out</button>
      </Authenticated>
      <Unauthenticated>
        <p>Please sign in.</p>
        <form onSubmit={(e) => {
          e.preventDefault();
          const formData = new FormData(e.currentTarget);
          const email = formData.get('email')?.toString();
          const password = formData.get('password')?.toString();
          if (email && password) {
            authClient.signIn.email({ email, password });
          }
        }}>
          <input type="email" name="email" placeholder="Email" required />
          <input type="password" name="password" placeholder="Password" required />
          <button type="submit">Sign In</button>
        </form>
      </Unauthenticated>
    </>
  );
}

// --- Root Render (src/main.tsx) ---
const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL ?? '');

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <ConvexBetterAuthProvider client={convex} authClient={authClient}>
      <App />
    </ConvexBetterAuthProvider>
  </React.StrictMode>
);

view raw JSON →