The @ave-id/sdk/next module provides client components for the App Router: AveSessionProvider, useAveSession, and optional AveConvexBridge.
Install
bun add @ave-id/sdk react convex
react is a peer dependency (18+).
App layout: session + Convex
AveSessionProvider must run in a client bundle. Keep a small Providers component and import it from layout.tsx.
// app/providers.tsx
"use client";
import { useMemo } from "react";
import { ConvexProvider, ConvexReactClient } from "convex/react";
import {
AveSessionProvider,
AveConvexBridge,
} from "@ave-id/sdk/next";
import { createLocalStorageAdapter } from "@ave-id/sdk";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
export function Providers({ children }: { children: React.ReactNode }) {
const sessionOptions = useMemo(
() => ({
oauth: {
clientId: process.env.NEXT_PUBLIC_AVE_CLIENT_ID!,
redirectUri: `${process.env.NEXT_PUBLIC_APP_URL ?? ""}/callback`,
},
storage: createLocalStorageAdapter(),
devtools: process.env.NODE_ENV === "development",
}),
[]
);
return (
<AveSessionProvider options={sessionOptions}>
<ConvexProvider client={convex}>
<AveConvexBridge client={convex}>{children}</AveConvexBridge>
</ConvexProvider>
</AveSessionProvider>
);
}
// app/layout.tsx
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
OAuth callback route
Use completeOAuthCallback from @ave-id/sdk/client in a client page (or call finishPkceLogin + session.setTokensFromResponse). The provider’s AveSession instance must be the same one — obtain it via useAveSession().session in a child component, or structure your callback as a component under AveSessionProvider and pass session from context.
Example: a /callback page that mounts only after login redirect can use useAveSession to run completeOAuthCallback once when searchParams.code is present.
Hooks
useAveSession() — { session, status, snapshot, isHydrated }. Wait for isHydrated before treating status === "signedOut" as definitive on first paint.
getAppKeyBase64() on session for E2EE after hydrate.
Last modified on May 1, 2026