use-convex 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +120 -41
  2. package/dist/module.d.mts +73 -31
  3. package/dist/module.mjs +73 -17
  4. package/dist/runtime/auth/oauth.d.ts +96 -0
  5. package/dist/runtime/auth/oauth.js +170 -0
  6. package/dist/runtime/auth/sessionRoutes.d.ts +37 -0
  7. package/dist/runtime/auth/sessionRoutes.js +41 -0
  8. package/dist/runtime/composables/useAuth.d.ts +81 -48
  9. package/dist/runtime/composables/useAuth.js +69 -398
  10. package/dist/runtime/composables/useAuthToken.d.ts +2 -2
  11. package/dist/runtime/composables/useAuthToken.js +4 -0
  12. package/dist/runtime/composables/useConvexAuth.js +1 -1
  13. package/dist/runtime/composables/useConvexPaginatedQuery.js +6 -1
  14. package/dist/runtime/composables/useConvexQueries.d.ts +36 -7
  15. package/dist/runtime/composables/useConvexQueries.js +37 -13
  16. package/dist/runtime/composables/useConvexQuery.js +6 -1
  17. package/dist/runtime/plugin.auth.client.d.ts +8 -3
  18. package/dist/runtime/plugin.auth.client.js +208 -23
  19. package/dist/runtime/plugin.server.js +8 -2
  20. package/dist/runtime/server/auth.d.ts +7 -2
  21. package/dist/runtime/server/auth.js +14 -3
  22. package/dist/runtime/server/convexAuth/refresh.d.ts +3 -0
  23. package/dist/runtime/server/convexAuth/refresh.js +5 -0
  24. package/dist/runtime/server/convexAuth/session.middleware.d.ts +10 -0
  25. package/dist/runtime/server/convexAuth/session.middleware.js +37 -0
  26. package/dist/runtime/server/convexAuth/setup.d.ts +21 -0
  27. package/dist/runtime/server/convexAuth/setup.js +90 -0
  28. package/dist/runtime/server/convexAuth/signin.d.ts +3 -0
  29. package/dist/runtime/server/convexAuth/signin.js +5 -0
  30. package/dist/runtime/server/convexAuth/signout.d.ts +3 -0
  31. package/dist/runtime/server/convexAuth/signout.js +5 -0
  32. package/dist/runtime/server/convexConfig.d.ts +2 -6
  33. package/dist/runtime/server/fetch.d.ts +9 -1
  34. package/dist/runtime/server/fetch.js +7 -10
  35. package/dist/runtime/utils/authClientOptions.d.ts +54 -0
  36. package/dist/runtime/utils/authClientOptions.js +10 -0
  37. package/dist/runtime/utils/authCookie.d.ts +8 -14
  38. package/dist/runtime/utils/authCookie.js +23 -27
  39. package/dist/runtime/utils/authStorage.d.ts +80 -42
  40. package/dist/runtime/utils/authStorage.js +56 -66
  41. package/dist/runtime/utils/context.d.ts +42 -6
  42. package/dist/runtime/utils/http.d.ts +7 -0
  43. package/dist/runtime/utils/http.js +5 -2
  44. package/dist/types.d.mts +6 -2
  45. package/package.json +10 -5
  46. package/dist/runtime/server/api/convex/auth/session.d.ts +0 -36
  47. package/dist/runtime/server/api/convex/auth/session.js +0 -90
  48. package/dist/runtime/server/authCookies.d.ts +0 -9
  49. package/dist/runtime/server/authCookies.js +0 -64
  50. package/dist/runtime/server/sameOrigin.d.ts +0 -14
  51. package/dist/runtime/server/sameOrigin.js +0 -29
  52. package/dist/runtime/utils/authMutex.d.ts +0 -15
  53. package/dist/runtime/utils/authMutex.js +0 -47
  54. package/dist/runtime/utils/oauthRedirect.d.ts +0 -5
  55. package/dist/runtime/utils/oauthRedirect.js +0 -13
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Runtime knobs for the Convex Auth client that can't live in serializable
3
+ * module options: a custom TokenStorage, extra ambient sign-ins, or a custom
4
+ * `replaceUrl`. Call {@link configureConvexAuth} from a client plugin with
5
+ * `enforce: 'pre'` so the options land before the auth plugin creates the
6
+ * client.
7
+ */
8
+ /**
9
+ * Token storage (`@convex-dev/auth/browser` `TokenStorage`). Methods may be
10
+ * sync or async, e.g. Capacitor Preferences or an encrypted store.
11
+ */
12
+ export type ConvexAuthTokenStorage = {
13
+ getItem: (key: string) => string | null | undefined | Promise<string | null | undefined>;
14
+ setItem: (key: string, value: string) => void | Promise<void>;
15
+ removeItem: (key: string) => void | Promise<void>;
16
+ };
17
+ export type { ConvexAuthStorageMode } from './authStorage.js';
18
+ /**
19
+ * An ambient sign-in registration (`AmbientSignInClient` in
20
+ * `@convex-dev/auth`): a method that finishes on its own at startup, like
21
+ * an OAuth callback. Typed loosely here so this file needs no Convex Auth
22
+ * import; the auth plugin passes it straight to `AuthClient`.
23
+ */
24
+ export type ConvexAmbientSignIn = {
25
+ id: string;
26
+ setup: (ctx: never) => void | {
27
+ onInit?: () => void;
28
+ };
29
+ };
30
+ export type ConvexAuthClientOptions = {
31
+ /**
32
+ * Custom token storage. Overrides `convex.auth.storage`.
33
+ */
34
+ storage?: ConvexAuthTokenStorage;
35
+ /**
36
+ * Replaces the default ambient sign-ins (`[oauth()]`). Pass `[]` to
37
+ * disable OAuth callback handling, or include `convexOAuth()` alongside
38
+ * your own.
39
+ */
40
+ ambientSignIns?: ConvexAmbientSignIn[];
41
+ /**
42
+ * Replace the page URL after an OAuth callback strips its params.
43
+ * Defaults to `history.replaceState`, then syncs `vue-router`.
44
+ */
45
+ replaceUrl?: (url: string) => void;
46
+ };
47
+ /**
48
+ * Set runtime Convex Auth knobs. Merge is shallow — later calls override
49
+ * earlier keys.
50
+ */
51
+ export declare function configureConvexAuth(options: ConvexAuthClientOptions): void;
52
+ export declare function getConvexAuthClientOptions(): ConvexAuthClientOptions;
53
+ /** @internal */
54
+ export declare function resetConvexAuthClientOptionsForTests(): void;
@@ -0,0 +1,10 @@
1
+ let runtimeOverrides = {};
2
+ export function configureConvexAuth(options) {
3
+ runtimeOverrides = { ...runtimeOverrides, ...options };
4
+ }
5
+ export function getConvexAuthClientOptions() {
6
+ return { ...runtimeOverrides };
7
+ }
8
+ export function resetConvexAuthClientOptionsForTests() {
9
+ runtimeOverrides = {};
10
+ }
@@ -1,19 +1,13 @@
1
- import { type ComputedRef } from 'vue';
1
+ import { type ComputedRef, type Ref } from 'vue';
2
2
  /**
3
- * Shared JWT cookie for SSR snapshots. Same name + options as persistTokens
4
- * so plugin reads and sign-in/out writes share one Nuxt cookie ref.
5
- *
6
- * When `auth.httpOnly` is set, this cookie is HttpOnly (server-readable only).
3
+ * Convex Auth access token shared between server and client via the Nuxt
4
+ * payload. The server fills it from the (refreshed) SSR session; the client
5
+ * auth plugin keeps it in sync with the live `AuthClient` token.
7
6
  */
7
+ export declare function useConvexAuthTokenState(): Ref<string | null>;
8
+ /** BYO providers: readable JWT cookie written by the app after sign-in. */
8
9
  export declare function useAuthJwtCookie(): import("nuxt/app").CookieRef<string | null> | undefined;
9
- /**
10
- * Readable presence marker used when JWT is HttpOnly so the client can still
11
- * compute `hasSsrSession` / `showAuthedUi` without reading the token.
12
- */
13
- export declare function useAuthPresentCookie(): import("nuxt/app").CookieRef<string | null> | undefined;
14
- /** Reactive JWT for HttpClient + SSR. Empty on the client when HttpOnly. */
10
+ /** Reactive JWT for HttpClient + SSR. */
15
11
  export declare function useSsrTokenRef(): ComputedRef<string | undefined>;
16
- /**
17
- * Session hint for UI gating: JWT readable, or HttpOnly presence cookie.
18
- */
12
+ /** Session hint for UI gating: a JWT is known for this request / client. */
19
13
  export declare function useHasSsrSessionRef(): ComputedRef<boolean>;
@@ -1,46 +1,42 @@
1
1
  import { computed } from "vue";
2
- import { useCookie, useRuntimeConfig } from "nuxt/app";
2
+ import { useCookie, useRuntimeConfig, useState } from "nuxt/app";
3
3
  import {
4
- AUTH_JWT_COOKIE_MAX_AGE,
4
+ SSR_TOKEN_STATE_KEY,
5
5
  cookieValueToSsrToken,
6
- isHttpOnlyAuth,
7
- resolveAuthCookieName,
8
- resolveAuthPresentCookieName
6
+ isConvexAuth,
7
+ resolveAuthCookieName
9
8
  } from "./authStorage.js";
10
- function cookieOptions(httpOnly) {
11
- return {
12
- sameSite: "lax",
13
- secure: process.env.NODE_ENV === "production",
14
- maxAge: AUTH_JWT_COOKIE_MAX_AGE,
15
- path: "/",
16
- httpOnly
17
- };
9
+ function readAuthConfig() {
10
+ const config = useRuntimeConfig();
11
+ return config.public.convex?.auth;
12
+ }
13
+ export function useConvexAuthTokenState() {
14
+ return useState(SSR_TOKEN_STATE_KEY, () => null);
18
15
  }
19
16
  export function useAuthJwtCookie() {
20
- const config = useRuntimeConfig();
21
- const convexConfig = config.public.convex;
22
- const name = resolveAuthCookieName(convexConfig?.auth);
23
- if (!name) {
17
+ const auth = readAuthConfig();
18
+ if (isConvexAuth(auth)) {
24
19
  return void 0;
25
20
  }
26
- const httpOnly = isHttpOnlyAuth(convexConfig?.auth);
27
- return useCookie(name, cookieOptions(httpOnly));
28
- }
29
- export function useAuthPresentCookie() {
30
- const config = useRuntimeConfig();
31
- const convexConfig = config.public.convex;
32
- const name = resolveAuthPresentCookieName(convexConfig?.auth);
21
+ const name = resolveAuthCookieName(auth);
33
22
  if (!name) {
34
23
  return void 0;
35
24
  }
36
- return useCookie(name, cookieOptions(false));
25
+ return useCookie(name, {
26
+ sameSite: "lax",
27
+ secure: process.env.NODE_ENV === "production",
28
+ path: "/"
29
+ });
37
30
  }
38
31
  export function useSsrTokenRef() {
32
+ if (isConvexAuth(readAuthConfig())) {
33
+ const state = useConvexAuthTokenState();
34
+ return computed(() => state.value || void 0);
35
+ }
39
36
  const cookie = useAuthJwtCookie();
40
37
  return computed(() => cookieValueToSsrToken(cookie?.value));
41
38
  }
42
39
  export function useHasSsrSessionRef() {
43
40
  const token = useSsrTokenRef();
44
- const present = useAuthPresentCookie();
45
- return computed(() => !!token.value || present?.value === "1");
41
+ return computed(() => !!token.value);
46
42
  }
@@ -1,55 +1,93 @@
1
1
  /**
2
- * Convex Auth client storage helpers (mirrors @convex-dev/auth/react).
2
+ * Shared auth configuration helpers.
3
+ *
4
+ * Kept free of `@convex-dev/auth` imports: apps that bring their own provider
5
+ * (Clerk, Auth0, custom JWT) load this file without installing Convex Auth.
3
6
  */
4
- export declare const JWT_STORAGE_KEY = "__convexAuthJWT";
5
- export declare const REFRESH_TOKEN_STORAGE_KEY = "__convexAuthRefreshToken";
6
- export declare const VERIFIER_STORAGE_KEY = "__convexAuthOAuthVerifier";
7
- export declare const AUTH_JWT_COOKIE_MAX_AGE: number;
8
- export declare const DEFAULT_CONVEX_AUTH_COOKIE = "convex_jwt";
9
- /** Readable marker so the client knows an HttpOnly session exists. */
10
- export declare const DEFAULT_AUTH_PRESENT_COOKIE = "convex_auth_present";
11
- /** HttpOnly JWT cookie (Next.js Convex Auth naming). */
12
- export declare const HTTPONLY_JWT_COOKIE = "__convexAuthJWT";
13
- /** HttpOnly refresh cookie. */
14
- export declare const HTTPONLY_REFRESH_COOKIE = "__convexAuthRefreshToken";
7
+ /** Session model for first-party Convex Auth v2. */
8
+ export type ConvexAuthMode = 'ssr' | 'spa';
9
+ /** Client token storage for Convex Auth. */
10
+ export type ConvexAuthStorageMode = 'localStorage' | 'inMemory';
11
+ /**
12
+ * Names of the session functions `setupConvexAuth` returns, as exported from
13
+ * the app's Convex functions (e.g. `convex/auth.ts` → `'auth:refreshSession'`).
14
+ */
15
+ export type ConvexAuthApiNames = {
16
+ refreshSession?: string;
17
+ signOut?: string;
18
+ isAuthenticated?: string;
19
+ };
15
20
  export type ConvexAuthConfig = {
16
- provider?: string;
17
- cookie?: string;
21
+ provider?: 'convex-auth';
18
22
  /**
19
- * Store JWT + refresh in HttpOnly cookies via Nitro (Next.js parity).
20
- * When true, JS cannot read tokens from `document.cookie`; `fetchToken`
21
- * uses same-origin POST `/api/convex/auth/session` with `{ getToken: true }`.
22
- * Prefer `true` in production. Does not make sessions XSS-proof.
23
+ * BYO providers: cookie whose value is a JWT for SSR queries and Nitro
24
+ * `fetch*` helpers. Ignored for `provider: 'convex-auth'`, which manages
25
+ * its own cookies.
23
26
  */
24
- httpOnly?: boolean;
25
- /** Readable presence cookie when `httpOnly` is set (UI only). */
26
- presentCookie?: string;
27
+ cookie?: string;
28
+ /** @see ModuleAuthOptions.mode */
29
+ mode?: ConvexAuthMode;
30
+ /** @see ModuleAuthOptions.api */
31
+ api?: ConvexAuthApiNames;
32
+ /** @see ModuleAuthOptions.routePrefix */
33
+ routePrefix?: string;
34
+ /** @see ModuleAuthOptions.storageNamespace */
35
+ storageNamespace?: string;
36
+ /** @see ModuleAuthOptions.storage */
37
+ storage?: ConvexAuthStorageMode;
38
+ /** @see ModuleAuthOptions.verbose */
39
+ verbose?: boolean;
40
+ };
41
+ /** Server-only Convex Auth options (`runtimeConfig.convexAuth`). */
42
+ export interface ConvexAuthServerRuntimeConfig {
43
+ /** Sign-in function names the auth proxy forwards, e.g. `'auth:signInWithUsernamePassword'`. */
44
+ signIn?: string[];
45
+ /** Origins trusted besides the request's own Host. */
46
+ allowedOrigins?: string[];
47
+ /** Cookie attributes. `secure` defaults to true except on localhost. */
48
+ cookie?: {
49
+ secure?: boolean;
50
+ domain?: string;
51
+ path?: string;
52
+ };
53
+ }
54
+ /** The Convex Auth v2 access-token cookie (fixed by `@convex-dev/auth/ssr`). */
55
+ export declare const CONVEX_AUTH_JWT_COOKIE = "__convexAuthJWT";
56
+ /** The Convex Auth v2 refresh-token cookie (fixed by `@convex-dev/auth/ssr`). */
57
+ export declare const CONVEX_AUTH_REFRESH_COOKIE = "__convexAuthRefreshToken";
58
+ export declare const DEFAULT_AUTH_ROUTE_PREFIX = "/api/convex/auth";
59
+ export declare const DEFAULT_CONVEX_AUTH_API: Required<ConvexAuthApiNames>;
60
+ /** `useState` key carrying the SSR access token to the client payload. */
61
+ export declare const SSR_TOKEN_STATE_KEY = "convex:auth-token";
62
+ export declare function isConvexAuth(auth?: ConvexAuthConfig): boolean;
63
+ /** SSR mode is the default for Convex Auth: Nuxt renders on the server. */
64
+ export declare function resolveAuthMode(auth?: ConvexAuthConfig): ConvexAuthMode;
65
+ export declare function isSsrConvexAuth(auth?: ConvexAuthConfig): boolean;
66
+ export declare function resolveAuthApiNames(auth?: ConvexAuthConfig): Required<ConvexAuthApiNames>;
67
+ export declare function resolveAuthRoutes(auth?: ConvexAuthConfig): {
68
+ signIn: string;
69
+ refresh: string;
70
+ signOut: string;
27
71
  };
28
- export declare function storageNamespace(url: string): string;
29
- export declare function storageKey(base: string, url: string): string;
30
- /**
31
- * Flatten FormData (or pass through a plain record) the same way the React
32
- * Convex Auth client does before calling `auth:signIn`.
33
- */
34
- export declare function flattenSignInParams(params?: FormData | Record<string, string>): Record<string, string>;
35
72
  /**
36
- * Resolve the auth cookie name for runtime config / SSR JWT reads.
37
- * When `provider === 'convex-auth'` and cookie is omitted, default to `convex_jwt`
38
- * (or the HttpOnly JWT name when `httpOnly` is enabled).
73
+ * Cookie holding the JWT for SSR reads: the Convex Auth access-token cookie
74
+ * in SSR mode, the configured cookie for BYO providers, otherwise none.
75
+ * Convex Auth SPA mode keeps tokens in browser storage, so it has no cookie.
39
76
  */
40
77
  export declare function resolveAuthCookieName(auth?: ConvexAuthConfig): string | undefined;
41
- export declare function resolveAuthPresentCookieName(auth?: ConvexAuthConfig): string | undefined;
42
- export declare function resolveAuthRefreshCookieName(auth?: ConvexAuthConfig): string | undefined;
43
- export declare function isHttpOnlyAuth(auth?: ConvexAuthConfig): boolean;
44
78
  /** Empty / missing cookies are not a session. */
45
79
  export declare function cookieValueToSsrToken(value: string | null | undefined): string | undefined;
46
- export declare function readLocal(key: string): string | null;
47
- export declare function writeLocal(key: string, value: string | null): void;
48
80
  /**
49
- * Whether the current URL's `?code=` should be treated as an OAuth callback.
50
- * Only true when we previously stored a verifier (we started the flow).
81
+ * Whether a JWT's `exp` claim is within `skewSeconds` of now (or unreadable).
82
+ * Signature is not checked — this only decides whether to refresh.
83
+ */
84
+ export declare function isJwtExpiring(token: string, skewSeconds?: number, nowMs?: number): boolean;
85
+ /**
86
+ * A stable identity for the session a JWT belongs to: `iss` + `sub`.
87
+ *
88
+ * Convex Auth rotates the access token every minute but keeps the session
89
+ * id in `sub`, so this changes on sign-in / sign-out / account switch, not
90
+ * on rotation. Tokens without readable claims fall back to the token itself
91
+ * (any change is treated as a new session). Empty for no token.
51
92
  */
52
- export declare function shouldConsumeOAuthCode(options: {
53
- code: string | null;
54
- verifier: string | null;
55
- }): boolean;
93
+ export declare function sessionKeyFromToken(token: string | null | undefined): string;
@@ -1,85 +1,75 @@
1
- export const JWT_STORAGE_KEY = "__convexAuthJWT";
2
- export const REFRESH_TOKEN_STORAGE_KEY = "__convexAuthRefreshToken";
3
- export const VERIFIER_STORAGE_KEY = "__convexAuthOAuthVerifier";
4
- export const AUTH_JWT_COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
5
- export const DEFAULT_CONVEX_AUTH_COOKIE = "convex_jwt";
6
- export const DEFAULT_AUTH_PRESENT_COOKIE = "convex_auth_present";
7
- export const HTTPONLY_JWT_COOKIE = "__convexAuthJWT";
8
- export const HTTPONLY_REFRESH_COOKIE = "__convexAuthRefreshToken";
9
- export function storageNamespace(url) {
10
- return url.replace(/[^a-z0-9]/gi, "");
1
+ export const CONVEX_AUTH_JWT_COOKIE = "__convexAuthJWT";
2
+ export const CONVEX_AUTH_REFRESH_COOKIE = "__convexAuthRefreshToken";
3
+ export const DEFAULT_AUTH_ROUTE_PREFIX = "/api/convex/auth";
4
+ export const DEFAULT_CONVEX_AUTH_API = {
5
+ refreshSession: "auth:refreshSession",
6
+ signOut: "auth:signOut",
7
+ isAuthenticated: "auth:isAuthenticated"
8
+ };
9
+ export const SSR_TOKEN_STATE_KEY = "convex:auth-token";
10
+ export function isConvexAuth(auth) {
11
+ return auth?.provider === "convex-auth";
11
12
  }
12
- export function storageKey(base, url) {
13
- return `${base}_${storageNamespace(url)}`;
13
+ export function resolveAuthMode(auth) {
14
+ return auth?.mode ?? "ssr";
14
15
  }
15
- export function flattenSignInParams(params) {
16
- if (params === void 0) {
17
- return {};
18
- }
19
- if (typeof FormData !== "undefined" && params instanceof FormData) {
20
- const out = {};
21
- params.forEach((value, key) => {
22
- if (typeof value === "string") {
23
- out[key] = value;
24
- }
25
- });
26
- return out;
27
- }
28
- return { ...params };
16
+ export function isSsrConvexAuth(auth) {
17
+ return isConvexAuth(auth) && resolveAuthMode(auth) === "ssr";
29
18
  }
30
- export function resolveAuthCookieName(auth) {
31
- if (auth?.httpOnly) {
32
- return auth.cookie ?? HTTPONLY_JWT_COOKIE;
33
- }
34
- if (auth?.cookie) {
35
- return auth.cookie;
36
- }
37
- if (auth?.provider === "convex-auth") {
38
- return DEFAULT_CONVEX_AUTH_COOKIE;
39
- }
40
- return void 0;
19
+ export function resolveAuthApiNames(auth) {
20
+ return { ...DEFAULT_CONVEX_AUTH_API, ...auth?.api };
41
21
  }
42
- export function resolveAuthPresentCookieName(auth) {
43
- if (!auth?.httpOnly) {
44
- return void 0;
45
- }
46
- return auth.presentCookie ?? DEFAULT_AUTH_PRESENT_COOKIE;
22
+ export function resolveAuthRoutes(auth) {
23
+ const prefix = (auth?.routePrefix ?? DEFAULT_AUTH_ROUTE_PREFIX).replace(/\/+$/, "");
24
+ return {
25
+ signIn: `${prefix}/signin`,
26
+ refresh: `${prefix}/refresh`,
27
+ signOut: `${prefix}/signout`
28
+ };
47
29
  }
48
- export function resolveAuthRefreshCookieName(auth) {
49
- if (!auth?.httpOnly) {
50
- return void 0;
30
+ export function resolveAuthCookieName(auth) {
31
+ if (isConvexAuth(auth)) {
32
+ return isSsrConvexAuth(auth) ? CONVEX_AUTH_JWT_COOKIE : void 0;
51
33
  }
52
- return HTTPONLY_REFRESH_COOKIE;
53
- }
54
- export function isHttpOnlyAuth(auth) {
55
- return auth?.httpOnly === true;
34
+ return auth?.cookie || void 0;
56
35
  }
57
36
  export function cookieValueToSsrToken(value) {
58
37
  return value || void 0;
59
38
  }
60
- export function readLocal(key) {
61
- if (typeof window === "undefined") {
62
- return null;
39
+ export function isJwtExpiring(token, skewSeconds = 10, nowMs = Date.now()) {
40
+ const payload = token.split(".")[1];
41
+ if (!payload) {
42
+ return true;
63
43
  }
64
44
  try {
65
- return window.localStorage.getItem(key);
45
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
46
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
47
+ const json = typeof atob === "function" ? atob(padded) : globalThis.Buffer.from(padded, "base64").toString();
48
+ const exp = JSON.parse(json).exp;
49
+ if (typeof exp !== "number") {
50
+ return true;
51
+ }
52
+ return exp * 1e3 - skewSeconds * 1e3 <= nowMs;
66
53
  } catch {
67
- return null;
54
+ return true;
68
55
  }
69
56
  }
70
- export function writeLocal(key, value) {
71
- if (typeof window === "undefined") {
72
- return;
57
+ export function sessionKeyFromToken(token) {
58
+ if (!token) {
59
+ return "";
73
60
  }
74
- try {
75
- if (value === null) {
76
- window.localStorage.removeItem(key);
77
- } else {
78
- window.localStorage.setItem(key, value);
61
+ const payload = token.split(".")[1];
62
+ if (payload) {
63
+ try {
64
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
65
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
66
+ const json = typeof atob === "function" ? atob(padded) : globalThis.Buffer.from(padded, "base64").toString();
67
+ const claims = JSON.parse(json);
68
+ if (typeof claims.sub === "string" && claims.sub) {
69
+ return `${typeof claims.iss === "string" ? claims.iss : ""}|${claims.sub}`;
70
+ }
71
+ } catch {
79
72
  }
80
- } catch {
81
73
  }
82
- }
83
- export function shouldConsumeOAuthCode(options) {
84
- return options.code !== null && options.verifier !== null;
74
+ return token;
85
75
  }
@@ -1,5 +1,7 @@
1
1
  import type { AuthTokenFetcher, ConvexClient, ConvexHttpClient } from 'convex/browser';
2
- import type { ComputedRef, InjectionKey, Ref } from 'vue';
2
+ import type { FunctionReference } from 'convex/server';
3
+ import type { ComputedRef, InjectionKey, Ref, ShallowRef } from 'vue';
4
+ import type { CreateHttpClientOptions } from './http.js';
3
5
  export interface ConvexAuthContext {
4
6
  /**
5
7
  * Whether useConvexAuth({ fetchToken }) has been called.
@@ -18,6 +20,36 @@ export interface ConvexAuthContext {
18
20
  isAuthenticated: Ref<boolean>;
19
21
  isRefreshing: Ref<boolean>;
20
22
  }
23
+ /** Snapshot of the Convex Auth client (`AuthState` in `@convex-dev/auth`). */
24
+ export interface ConvexAuthSnapshot {
25
+ isLoading: boolean;
26
+ isAuthenticated: boolean;
27
+ token: string | null;
28
+ }
29
+ /**
30
+ * Runs a method's sign-in function. Direct to the deployment in SPA mode,
31
+ * through the Nitro auth proxy in SSR mode (which moves the refresh token
32
+ * into an httpOnly cookie).
33
+ */
34
+ export interface ConvexAuthSignInApi {
35
+ mutation: (fn: FunctionReference<'mutation'>, args: Record<string, unknown>) => Promise<any>;
36
+ action: (fn: FunctionReference<'action'>, args: Record<string, unknown>) => Promise<any>;
37
+ }
38
+ /** First-party Convex Auth v2 binding, set by the auth client plugin. */
39
+ export interface ConvexAuthBinding {
40
+ mode: 'ssr' | 'spa';
41
+ state: ShallowRef<ConvexAuthSnapshot>;
42
+ signInApi: ConvexAuthSignInApi;
43
+ /** Adopt a session returned by a method's sign-in function. */
44
+ setSession: (session: {
45
+ accessToken: string;
46
+ userId: string;
47
+ [key: string]: unknown;
48
+ }) => Promise<void>;
49
+ signOut: () => Promise<void>;
50
+ /** Values an ambient sign-in (e.g. OAuth) publishes, read reactively. */
51
+ ambientValue: <T>(id: string, key: string) => Readonly<Ref<T | undefined>>;
52
+ }
21
53
  export interface ConvexNuxtContext {
22
54
  url: string;
23
55
  /**
@@ -25,21 +57,25 @@ export interface ConvexNuxtContext {
25
57
  */
26
58
  client: ConvexClient | null;
27
59
  /**
28
- * JWT from the optional auth cookie. Reactive so sign-in/out updates
29
- * HttpClient refreshes and `hasSsrSession`.
60
+ * JWT for HttpClient snapshots: the SSR session token (Convex Auth SSR
61
+ * mode or a BYO cookie), then the live Convex Auth access token on the
62
+ * client. Reactive so sign-in/out re-runs HttpClient fetches.
30
63
  */
31
64
  ssrToken: ComputedRef<string | undefined>;
32
65
  /**
33
66
  * Shared auth state for useConvexAuth.
34
67
  */
35
68
  auth: ConvexAuthContext;
69
+ /**
70
+ * Convex Auth v2 client binding (`convex.auth.provider: 'convex-auth'`,
71
+ * browser only). `null` on the server and for BYO providers.
72
+ */
73
+ convexAuth?: ConvexAuthBinding | null;
36
74
  /**
37
75
  * Create a fresh HttpClient for one-shot fetches (SSR / Nitro / refresh).
38
76
  * Prefer a new client per call — HttpClient is stateful.
39
77
  */
40
- createHttpClient: (options?: {
41
- token?: string;
42
- }) => ConvexHttpClient;
78
+ createHttpClient: (options?: CreateHttpClientOptions) => ConvexHttpClient;
43
79
  }
44
80
  export declare const convexNuxtKey: InjectionKey<ConvexNuxtContext>;
45
81
  export declare function createAuthContext(): ConvexAuthContext;
@@ -1,6 +1,13 @@
1
1
  import { ConvexHttpClient } from 'convex/browser';
2
2
  export interface CreateHttpClientOptions {
3
3
  token?: string;
4
+ /**
5
+ * Deploy / admin key for privileged HttpClient calls (Next.js
6
+ * `fetchQuery(..., { adminToken })` parity). Uses `Authorization: Convex …`
7
+ * and clears any user JWT. Prefer per-request secrets — never put this in
8
+ * public runtime config.
9
+ */
10
+ adminToken?: string;
4
11
  skipConvexDeploymentUrlCheck?: boolean;
5
12
  }
6
13
  /**
@@ -2,9 +2,12 @@ import { ConvexHttpClient } from "convex/browser";
2
2
  export function createHttpClient(url, options = {}) {
3
3
  const client = new ConvexHttpClient(url, {
4
4
  skipConvexDeploymentUrlCheck: options.skipConvexDeploymentUrlCheck,
5
- ...options.token ? { auth: options.token } : {}
5
+ ...options.token && !options.adminToken ? { auth: options.token } : {}
6
6
  });
7
- if (options.token) {
7
+ if (options.adminToken) {
8
+ ;
9
+ client.setAdminAuth(options.adminToken);
10
+ } else if (options.token) {
8
11
  client.setAuth(options.token);
9
12
  }
10
13
  ;
package/dist/types.d.mts CHANGED
@@ -4,7 +4,7 @@ declare module '@nuxt/schema' {
4
4
  interface PublicRuntimeConfig extends ModulePublicRuntimeConfig {}
5
5
  }
6
6
 
7
- export { type AuthTokens, type SignInResult, type UseAuthReturn } from '../dist/runtime/composables/useAuth.js'
7
+ export { type ConvexAuthSession, type ConvexSignInResult, type OAuthCompleteResult, type OAuthFlowError, type OAuthProviderRefs, type OAuthSignInOptions, type OAuthStartResult, type UseAuthReturn } from '../dist/runtime/composables/useAuth.js'
8
8
 
9
9
  export { type ConvexQueryArgs, type UseConvexQueryOptions, type UseConvexQueryReturn } from '../dist/runtime/composables/useConvexQuery.js'
10
10
 
@@ -18,7 +18,7 @@ export { type ConvexR2UploadApi, type ConvexR2UploadProgress } from '../dist/run
18
18
 
19
19
  export { type PaginatedQueryArgs, type PaginatedQueryItem, type PaginatedQueryReference, type PaginationStatus, type UseConvexPaginatedQueryOptions, type UseConvexPaginatedQueryReturn } from '../dist/runtime/composables/useConvexPaginatedQuery.js'
20
20
 
21
- export { type ConvexQueriesRequest, type ConvexQueriesResult, type ConvexQueryRequestEntry } from '../dist/runtime/composables/useConvexQueries.js'
21
+ export { type ConvexQueriesRequest, type ConvexQueriesResult, type ConvexQueryRequestEntry, type UseConvexQueriesOptions } from '../dist/runtime/composables/useConvexQueries.js'
22
22
 
23
23
  export { type ConvexFetchOptions } from '../dist/runtime/server/fetch.js'
24
24
 
@@ -30,6 +30,10 @@ export { type ConnectionState } from '../dist/runtime/composables/useConvexConne
30
30
 
31
31
  export { type ConvexGate } from '../dist/runtime/composables/useConvexGate.js'
32
32
 
33
+ export { type ConvexAmbientSignIn, type ConvexAuthClientOptions, type ConvexAuthStorageMode, type ConvexAuthTokenStorage, type configureConvexAuth } from '../dist/runtime/utils/authClientOptions.js'
34
+
35
+ export { type ConvexAuthServerRuntimeConfig } from '../dist/runtime/utils/authStorage.js'
36
+
33
37
  export { default } from './module.mjs'
34
38
 
35
39
  export { type ModuleAuthOptions, type ModuleOptions, type ModulePublicRuntimeConfig } from './module.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "use-convex",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "First-class Convex integration for Nuxt",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -44,13 +44,12 @@
44
44
  "h3": "^1.15.0"
45
45
  },
46
46
  "devDependencies": {
47
- "@auth/core": "0.41.1",
48
- "@convex-dev/auth": "^0.0.95",
47
+ "@convex-dev/auth": "^2.0.0",
49
48
  "@nuxt/module-builder": "^1.0.0",
50
49
  "@nuxt/schema": "^4.0.0",
51
50
  "@nuxt/test-utils": "^3.23.0",
52
51
  "@types/node": "^26.5.0",
53
- "convex": "^1.46.0",
52
+ "convex": "^1.48.0",
54
53
  "convex-test": "^0.0.56",
55
54
  "happy-dom": "^20.14.0",
56
55
  "nitropack": "^2.13.0",
@@ -63,10 +62,16 @@
63
62
  "vue-tsc": "^3.0.0"
64
63
  },
65
64
  "peerDependencies": {
66
- "convex": "^1.46.0",
65
+ "@convex-dev/auth": "^2.0.0",
66
+ "convex": "^1.48.0",
67
67
  "nuxt": "^4.0.0",
68
68
  "vue": "^3.5.0"
69
69
  },
70
+ "peerDependenciesMeta": {
71
+ "@convex-dev/auth": {
72
+ "optional": true
73
+ }
74
+ },
70
75
  "packageManager": "pnpm@10.0.0",
71
76
  "pnpm": {
72
77
  "overrides": {