From 3f6f09a82d4b4b4e62f3444d360a5149bdf422f1 Mon Sep 17 00:00:00 2001 From: Christian Wyglendowski Date: Tue, 3 Dec 2024 15:01:04 -0500 Subject: [PATCH 1/7] Use a Convex function for Next.js auth checks If the auth token doesn't validate on the Convex backend, then it's considered invalid and thus unauthenticated. --- src/nextjs/server/index.tsx | 8 ++++- src/server/implementation/index.ts | 16 ++++++++++ test-nextjs/convex/auth.ts | 2 +- test-nextjs/e2e-tests/invalid-auth.spec.ts | 36 ++++++++++++++++++++++ test-nextjs/e2e-tests/signin.spec.ts | 2 ++ test-nextjs/playwright.config.ts | 2 ++ 6 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 test-nextjs/e2e-tests/invalid-auth.spec.ts diff --git a/src/nextjs/server/index.tsx b/src/nextjs/server/index.tsx index 23adf3e..9a20bbf 100644 --- a/src/nextjs/server/index.tsx +++ b/src/nextjs/server/index.tsx @@ -1,5 +1,6 @@ import "server-only"; +import { fetchQuery } from "convex/nextjs"; import { NextMiddlewareResult } from "next/dist/server/web/types"; import { NextFetchEvent, @@ -20,6 +21,7 @@ import { setAuthCookies, setAuthCookiesInMiddleware, } from "./utils.js"; +import { IsAuthenticatedQuery } from "../../server/implementation/index.js"; /** * Wrap your app with this provider in your root `layout.tsx`. @@ -230,7 +232,11 @@ export function convexAuthNextjsMiddleware( }, isAuthenticated: async () => { const cookies = await getRequestCookiesInMiddleware(request); - return (cookies.token ?? undefined) !== undefined; + try { + return await fetchQuery("auth:isAuthenticated" as any as IsAuthenticatedQuery, {}, {token: cookies.token ?? undefined}); + } catch { + return false; + } }, }, })) ?? diff --git a/src/server/implementation/index.ts b/src/server/implementation/index.ts index 1cfa056..a94a245 100644 --- a/src/server/implementation/index.ts +++ b/src/server/implementation/index.ts @@ -7,6 +7,7 @@ import { HttpRouter, WithoutSystemFields, actionGeneric, + queryGeneric, httpActionGeneric, internalMutationGeneric, } from "convex/server"; @@ -64,6 +65,12 @@ export type SignInAction = FunctionReferenceFromExport< export type SignOutAction = FunctionReferenceFromExport< ReturnType["signOut"] >; +/** + * @internal + */ +export type IsAuthenticatedQuery = FunctionReferenceFromExport< + ReturnType["isAuthenticated"] +>; /** * Configure the Convex Auth library. Returns an object with @@ -434,6 +441,15 @@ export function convexAuth(config_: ConvexAuthConfig) { return storeImpl(ctx, args, getProviderOrThrow, config); }, }), + + /** + * Utility function for frameworks to use to get the current auth state + * based on credentials that they've supplied separately. + */ + isAuthenticated: queryGeneric({args: {}, handler: async (ctx, _args): Promise => { + const ident = await ctx.auth.getUserIdentity(); + return ident !== null; + }}), }; } diff --git a/test-nextjs/convex/auth.ts b/test-nextjs/convex/auth.ts index 923a99e..0a4d47e 100644 --- a/test-nextjs/convex/auth.ts +++ b/test-nextjs/convex/auth.ts @@ -3,7 +3,7 @@ import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; import { internal } from "./_generated/api"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ GitHub, ConvexCredentials({ diff --git a/test-nextjs/e2e-tests/invalid-auth.spec.ts b/test-nextjs/e2e-tests/invalid-auth.spec.ts new file mode 100644 index 0000000..1e5f067 --- /dev/null +++ b/test-nextjs/e2e-tests/invalid-auth.spec.ts @@ -0,0 +1,36 @@ +import { test } from "@playwright/test"; +import { SignJWT } from "jose"; + +test("invalid auth cookie redirects to signin page", async ({ + page, + context, +}) => { + // Create a fake JWT that's otherwise valid. + const expirationTime = new Date( + Date.now() + 12 * 60 * 60 * 1000, // 12 hours in the future + ); + const jwt = await new SignJWT({ + sub: "blahblahblah", + }) + .setProtectedHeader({ alg: "HS256" }) + .setIssuedAt() + .setIssuer("https://example.com") + .setAudience("convex") + .setExpirationTime(expirationTime) + .sign(new TextEncoder().encode("")); + + // Set cookies for the fake JWT and a junk refresh token too. + await context.addCookies([ + { name: "__convexAuthJWT", value: jwt, path: "/", domain: "127.0.0.1" }, + { + name: "__convexAuthRefreshToken", + value: "foobar", + path: "/", + domain: "127.0.0.1", + }, + ]); + + // An attempt to go to a protected route should redirect to sign-in. + await page.goto("/product"); + await page.waitForURL("/signin"); +}); diff --git a/test-nextjs/e2e-tests/signin.spec.ts b/test-nextjs/e2e-tests/signin.spec.ts index 86ccc07..80d2598 100644 --- a/test-nextjs/e2e-tests/signin.spec.ts +++ b/test-nextjs/e2e-tests/signin.spec.ts @@ -5,6 +5,8 @@ test("signin fails correctly", async ({ page }) => { await page.getByRole("link").getByText("Get Started").first().click(); + await page.waitForURL("/signin"); + await page .getByLabel("Secret") .fill( diff --git a/test-nextjs/playwright.config.ts b/test-nextjs/playwright.config.ts index 0d76468..7e139f3 100644 --- a/test-nextjs/playwright.config.ts +++ b/test-nextjs/playwright.config.ts @@ -77,5 +77,7 @@ export default defineConfig({ : "npm run dev:frontend", url: "http://127.0.0.1:3000", reuseExistingServer: !process.env.CI, + stdout: "ignore", // Set to "pipe" if you're debugging a failing test. + stderr: "pipe", }, }); From 9083932bf8757fde4cb5c9e74c3d09aa5ff1ec1c Mon Sep 17 00:00:00 2001 From: Christian Wyglendowski Date: Wed, 4 Dec 2024 13:22:26 -0500 Subject: [PATCH 2/7] Update formatting --- src/nextjs/server/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/nextjs/server/index.tsx b/src/nextjs/server/index.tsx index 9a20bbf..dcf0da7 100644 --- a/src/nextjs/server/index.tsx +++ b/src/nextjs/server/index.tsx @@ -233,7 +233,11 @@ export function convexAuthNextjsMiddleware( isAuthenticated: async () => { const cookies = await getRequestCookiesInMiddleware(request); try { - return await fetchQuery("auth:isAuthenticated" as any as IsAuthenticatedQuery, {}, {token: cookies.token ?? undefined}); + return await fetchQuery( + "auth:isAuthenticated" as any as IsAuthenticatedQuery, + {}, + { token: cookies.token ?? undefined }, + ); } catch { return false; } From 8e2face45fa206e7b29a13b218348c3ff71fadb2 Mon Sep 17 00:00:00 2001 From: Christian Wyglendowski Date: Tue, 10 Dec 2024 10:54:29 -0500 Subject: [PATCH 3/7] Apply review feedback `isAuthenticatedNextJs` now checks w/ the Convex backend too. --- src/nextjs/server/index.tsx | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/nextjs/server/index.tsx b/src/nextjs/server/index.tsx index dcf0da7..5c0b3c8 100644 --- a/src/nextjs/server/index.tsx +++ b/src/nextjs/server/index.tsx @@ -94,7 +94,8 @@ export async function convexAuthNextjsToken() { * since they won't stop nested pages from rendering. */ export async function isAuthenticatedNextjs() { - return (await convexAuthNextjsToken()) !== undefined; + const cookies = await getRequestCookies(); + return isAuthenticated(cookies.token); } /** @@ -232,15 +233,7 @@ export function convexAuthNextjsMiddleware( }, isAuthenticated: async () => { const cookies = await getRequestCookiesInMiddleware(request); - try { - return await fetchQuery( - "auth:isAuthenticated" as any as IsAuthenticatedQuery, - {}, - { token: cookies.token ?? undefined }, - ); - } catch { - return false; - } + return isAuthenticated(cookies.token); }, }, })) ?? @@ -304,3 +297,18 @@ async function convexAuthNextjsServerState(): Promise { _timeFetched: Date.now(), }; } + +async function isAuthenticated(token: string | null): Promise { + if (!token) { + return false; + } + try { + return await fetchQuery( + "auth:isAuthenticated" as any as IsAuthenticatedQuery, + {}, + { token: token }, + ); + } catch { + return false; + } +} From 8adc23cbfb632e7c702e85ffea505b8cefea5133 Mon Sep 17 00:00:00 2001 From: Christian Wyglendowski Date: Tue, 10 Dec 2024 11:31:47 -0500 Subject: [PATCH 4/7] Add a test for a Route Handler that uses isAuthenticatedNextJs --- test-nextjs/app/api/route.ts | 9 +++++ .../e2e-tests/route-handler-with-auth.spec.ts | 33 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 test-nextjs/app/api/route.ts create mode 100644 test-nextjs/e2e-tests/route-handler-with-auth.spec.ts diff --git a/test-nextjs/app/api/route.ts b/test-nextjs/app/api/route.ts new file mode 100644 index 0000000..8fe9874 --- /dev/null +++ b/test-nextjs/app/api/route.ts @@ -0,0 +1,9 @@ +import { isAuthenticatedNextjs } from "../../../dist/nextjs/server/index.js"; + +export async function GET() { + const isAuthenticated = await isAuthenticatedNextjs(); + return Response.json( + { someData: isAuthenticated }, + { status: isAuthenticated ? 200 : 403 }, + ); +} diff --git a/test-nextjs/e2e-tests/route-handler-with-auth.spec.ts b/test-nextjs/e2e-tests/route-handler-with-auth.spec.ts new file mode 100644 index 0000000..b97ac1a --- /dev/null +++ b/test-nextjs/e2e-tests/route-handler-with-auth.spec.ts @@ -0,0 +1,33 @@ +import { test, expect, Page } from "@playwright/test"; + +test("route handler returns 403 when not authenticated", async ({ page }) => { + const response = await page.goto("/api/"); + + expect(response).not.toBeNull(); + expect(response?.status()).toBe(403); +}); + +test("route handler returns 200 when authenticated", async ({ page }) => { + await signIn(page); + + + const response = await page.goto("/api/"); + + expect(response).not.toBeNull(); + expect(response?.status()).toBe(200); + + await signOut(page); +}); + +async function signIn(page: Page) { + await page.goto("/signin"); + await page.getByLabel("Secret").fill(process.env.AUTH_E2E_TEST_SECRET!); + await page.getByRole("button").getByText("Sign in with secret").click(); + await page.waitForURL("/product"); +} + +async function signOut(page: Page) { + await page.goto("/product"); + await page.getByRole("button", { name: "user menu" }).click(); + await page.getByRole("menuitem").getByText("Sign out").click(); +} \ No newline at end of file From a263ab1112e8fd4086d0330222dc53d7d7f4c5f1 Mon Sep 17 00:00:00 2001 From: Christian Wyglendowski Date: Tue, 10 Dec 2024 13:08:56 -0500 Subject: [PATCH 5/7] Update doc and call-sites for convexAuth We now unpack the isAuthenticated function in all of them. --- docs/pages/advanced.mdx | 6 ++--- docs/pages/api_reference/nextjs/server.mdx | 2 +- .../api_reference/providers/Anonymous.mdx | 2 +- .../providers/ConvexCredentials.mdx | 2 +- docs/pages/api_reference/providers/Email.mdx | 2 +- .../api_reference/providers/Password.mdx | 2 +- docs/pages/api_reference/server.mdx | 24 ++++++++++++------- docs/pages/config/anonymous.mdx | 4 ++-- docs/pages/config/email.mdx | 2 +- docs/pages/config/oauth.mdx | 6 ++--- docs/pages/config/otps.mdx | 2 +- docs/pages/config/passwords.mdx | 6 ++--- docs/pages/setup/manual.mdx | 2 +- src/cli/index.ts | 2 +- src/providers/Anonymous.ts | 2 +- src/providers/ConvexCredentials.ts | 2 +- src/providers/Email.ts | 2 +- src/providers/Password.ts | 2 +- src/server/implementation/index.ts | 2 +- src/server/types.ts | 2 +- test-router/convex/auth.ts | 2 +- test/convex/auth.ts | 2 +- 22 files changed, 43 insertions(+), 37 deletions(-) diff --git a/docs/pages/advanced.mdx b/docs/pages/advanced.mdx index 209305a..06ccaeb 100644 --- a/docs/pages/advanced.mdx +++ b/docs/pages/advanced.mdx @@ -34,7 +34,7 @@ Convex Auth follows this logic: import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; - export const { auth, signIn, signOut, store } = convexAuth({ + export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ Resend, GitHub({ allowDangerousEmailAccountLinking: false }), @@ -76,7 +76,7 @@ import GitHub from "@auth/core/providers/github"; import Password from "@convex-dev/auth/providers/Password"; import { MutationCtx } from "./_generated/server"; -export const { auth, signIn, signOut, store } = { +export const { auth, signIn, signOut, store, isAuthenticated } = { providers: [GitHub, Password], callbacks: { // `args.type` is one of "oauth" | "email" | "phone" | "credentials" | "verification" @@ -118,7 +118,7 @@ import GitHub from "@auth/core/providers/github"; import Password from "@convex-dev/auth/providers/Password"; import { MutationCtx } from "./_generated/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [GitHub, Password], callbacks: { // `args` are the same the as for `createOrUpdateUser` but include `userId` diff --git a/docs/pages/api_reference/nextjs/server.mdx b/docs/pages/api_reference/nextjs/server.mdx index 57094e5..dabb353 100644 --- a/docs/pages/api_reference/nextjs/server.mdx +++ b/docs/pages/api_reference/nextjs/server.mdx @@ -137,7 +137,7 @@ and [useAuthActions](/api_reference/react#useauthactions).

Defined in

-[src/nextjs/server/index.tsx:27](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L27) +[src/nextjs/server/index.tsx:29](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L29) *** diff --git a/docs/pages/api_reference/providers/Anonymous.mdx b/docs/pages/api_reference/providers/Anonymous.mdx index c6bea78..0e1e8eb 100644 --- a/docs/pages/api_reference/providers/Anonymous.mdx +++ b/docs/pages/api_reference/providers/Anonymous.mdx @@ -6,7 +6,7 @@ Configure [Anonymous](Anonymous.mdx#anonymous) provider given an [AnonymousConfi import Anonymous from "@convex-dev/auth/providers/Anonymous"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Anonymous], }); ``` diff --git a/docs/pages/api_reference/providers/ConvexCredentials.mdx b/docs/pages/api_reference/providers/ConvexCredentials.mdx index 6255394..d789732 100644 --- a/docs/pages/api_reference/providers/ConvexCredentials.mdx +++ b/docs/pages/api_reference/providers/ConvexCredentials.mdx @@ -9,7 +9,7 @@ use the [`Password`](/api_reference/providers/Password) provider instead. import ConvexCredentials from "@convex-dev/auth/providers/ConvexCredentials"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ ConvexCredentials({ authorize: async (credentials, ctx) => { diff --git a/docs/pages/api_reference/providers/Email.mdx b/docs/pages/api_reference/providers/Email.mdx index 09b056f..45621d2 100644 --- a/docs/pages/api_reference/providers/Email.mdx +++ b/docs/pages/api_reference/providers/Email.mdx @@ -19,7 +19,7 @@ you can override the `authorize` method to skip the check: import Email from "@convex-dev/auth/providers/Email"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ Email({ authorize: undefined }), ], diff --git a/docs/pages/api_reference/providers/Password.mdx b/docs/pages/api_reference/providers/Password.mdx index 6262933..3979d8d 100644 --- a/docs/pages/api_reference/providers/Password.mdx +++ b/docs/pages/api_reference/providers/Password.mdx @@ -16,7 +16,7 @@ by the `flow` parameter: import Password from "@convex-dev/auth/providers/Password"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Password], }); ``` diff --git a/docs/pages/api_reference/server.mdx b/docs/pages/api_reference/server.mdx index 4bbb78a..d219b32 100644 --- a/docs/pages/api_reference/server.mdx +++ b/docs/pages/api_reference/server.mdx @@ -18,7 +18,7 @@ from `convex/auth.ts` to make them callable: ```ts filename="convex/auth.ts" import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [], }); ``` @@ -131,9 +131,15 @@ Action called by the client to invalidate the current session. Internal mutation used by the library to read and write to the database during signin and signout. +#### isAuthenticated + + +Utility function for frameworks to use to get the current auth state +based on credentials that they've supplied separately. +

Defined in

-[src/server/implementation/index.ts:82](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L82) +[src/server/implementation/index.ts:91](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L91) *** @@ -211,7 +217,7 @@ the user ID or `null` if the client isn't authenticated

Defined in

-[src/server/implementation/index.ts:440](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L440) +[src/server/implementation/index.ts:479](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L479) *** @@ -411,7 +417,7 @@ or throws an error.

Defined in

-[src/server/implementation/index.ts:458](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L458) +[src/server/implementation/index.ts:497](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L497) *** @@ -554,7 +560,7 @@ secret does not match.

Defined in

-[src/server/implementation/index.ts:518](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L518) +[src/server/implementation/index.ts:557](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L557) *** @@ -685,7 +691,7 @@ The new secret credential to store for this account.

Defined in

-[src/server/implementation/index.ts:558](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L558) +[src/server/implementation/index.ts:597](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L597) *** @@ -757,7 +763,7 @@ Use this function to invalidate existing sessions.

Defined in

-[src/server/implementation/index.ts:588](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L588) +[src/server/implementation/index.ts:627](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L627) *** @@ -847,7 +853,7 @@ or `null`.

Defined in

-[src/server/implementation/index.ts:610](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L610) +[src/server/implementation/index.ts:649](https://github.com/get-convex/convex-auth/blob/main/src/server/implementation/index.ts#L649) *** @@ -1125,7 +1131,7 @@ and for magic links: import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [GitHub], callbacks: { async redirect({ redirectTo }) { diff --git a/docs/pages/config/anonymous.mdx b/docs/pages/config/anonymous.mdx index f305db6..babd7da 100644 --- a/docs/pages/config/anonymous.mdx +++ b/docs/pages/config/anonymous.mdx @@ -31,7 +31,7 @@ You can import the `Anonymous` provider from import { Anonymous } from "@convex-dev/auth/providers/Anonymous"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Anonymous], }); ``` @@ -101,7 +101,7 @@ This example matches the Cloudflare Turnstile API: import { Anonymous } from "@convex-dev/auth/providers/Anonymous"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ Anonymous({ profile({ token }) { diff --git a/docs/pages/config/email.mdx b/docs/pages/config/email.mdx index 77ae6e8..6bee0d1 100644 --- a/docs/pages/config/email.mdx +++ b/docs/pages/config/email.mdx @@ -71,7 +71,7 @@ Import Auth.js providers from `@auth/core/providers`. For example for _Resend_: import Resend from "@auth/core/providers/resend"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Resend], }); ``` diff --git a/docs/pages/config/oauth.mdx b/docs/pages/config/oauth.mdx index c4a2358..e04e442 100644 --- a/docs/pages/config/oauth.mdx +++ b/docs/pages/config/oauth.mdx @@ -97,7 +97,7 @@ Import Auth.js providers from `@auth/core/providers`. For example for _GitHub_: import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [GitHub], }); ``` @@ -190,7 +190,7 @@ example: import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [GitHub], callbacks: { async redirect({ redirectTo }) { @@ -246,7 +246,7 @@ config: import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ GitHub({ profile(githubProfile, tokens) { diff --git a/docs/pages/config/otps.mdx b/docs/pages/config/otps.mdx index a6bedeb..31fcbf6 100644 --- a/docs/pages/config/otps.mdx +++ b/docs/pages/config/otps.mdx @@ -101,7 +101,7 @@ Then use it in `convex/auth.ts`: import { convexAuth } from "@convex-dev/auth/server"; import { ResendOTP } from "./ResendOTP"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ResendOTP], }); ``` diff --git a/docs/pages/config/passwords.mdx b/docs/pages/config/passwords.mdx index 1140d59..f55fada 100644 --- a/docs/pages/config/passwords.mdx +++ b/docs/pages/config/passwords.mdx @@ -35,7 +35,7 @@ You can import the `Password` provider from import { Password } from "@convex-dev/auth/providers/Password"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Password], }); ``` @@ -210,7 +210,7 @@ import { Password } from "@convex-dev/auth/providers/Password"; import { convexAuth } from "@convex-dev/auth/server"; import { ResendOTPPasswordReset } from "./ResendOTPPasswordReset"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Password({ reset: ResendOTPPasswordReset })], }); ``` @@ -333,7 +333,7 @@ import { Password } from "@convex-dev/auth/providers/Password"; import { convexAuth } from "@convex-dev/auth/server"; import { ResendOTP } from "./ResendOTP"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Password({ verify: ResendOTP })], }); ``` diff --git a/docs/pages/setup/manual.mdx b/docs/pages/setup/manual.mdx index 8e564cf..6d713ca 100644 --- a/docs/pages/setup/manual.mdx +++ b/docs/pages/setup/manual.mdx @@ -105,7 +105,7 @@ export default { ```ts filename="convex/auth.ts" import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [], }); ``` diff --git a/src/cli/index.ts b/src/cli/index.ts index 76c87ad..40c72e5 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -423,7 +423,7 @@ async function initializeAuth(config: ProjectConfig) { const sourceTemplate = `\ import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({$$ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({$$ providers: [$$],$$ }); `; diff --git a/src/providers/Anonymous.ts b/src/providers/Anonymous.ts index ef0b5cc..b832357 100644 --- a/src/providers/Anonymous.ts +++ b/src/providers/Anonymous.ts @@ -5,7 +5,7 @@ * import Anonymous from "@convex-dev/auth/providers/Anonymous"; * import { convexAuth } from "@convex-dev/auth/server"; * - * export const { auth, signIn, signOut, store } = convexAuth({ + * export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ * providers: [Anonymous], * }); * ``` diff --git a/src/providers/ConvexCredentials.ts b/src/providers/ConvexCredentials.ts index 2fa0e33..2f179c9 100644 --- a/src/providers/ConvexCredentials.ts +++ b/src/providers/ConvexCredentials.ts @@ -8,7 +8,7 @@ * import ConvexCredentials from "@convex-dev/auth/providers/ConvexCredentials"; * import { convexAuth } from "@convex-dev/auth/server"; * - * export const { auth, signIn, signOut, store } = convexAuth({ + * export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ * providers: [ * ConvexCredentials({ * authorize: async (credentials, ctx) => { diff --git a/src/providers/Email.ts b/src/providers/Email.ts index bac6aba..370141a 100644 --- a/src/providers/Email.ts +++ b/src/providers/Email.ts @@ -22,7 +22,7 @@ import { EmailConfig, EmailUserConfig } from "../server/types.js"; * import Email from "@convex-dev/auth/providers/Email"; * import { convexAuth } from "@convex-dev/auth/server"; * - * export const { auth, signIn, signOut, store } = convexAuth({ + * export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ * providers: [ * Email({ authorize: undefined }), * ], diff --git a/src/providers/Password.ts b/src/providers/Password.ts index 2b89405..d6defec 100644 --- a/src/providers/Password.ts +++ b/src/providers/Password.ts @@ -15,7 +15,7 @@ * import Password from "@convex-dev/auth/providers/Password"; * import { convexAuth } from "@convex-dev/auth/server"; * - * export const { auth, signIn, signOut, store } = convexAuth({ + * export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ * providers: [Password], * }); * ``` diff --git a/src/server/implementation/index.ts b/src/server/implementation/index.ts index a94a245..20a2857 100644 --- a/src/server/implementation/index.ts +++ b/src/server/implementation/index.ts @@ -80,7 +80,7 @@ export type IsAuthenticatedQuery = FunctionReferenceFromExport< * ```ts filename="convex/auth.ts" * import { convexAuth } from "@convex-dev/auth/server"; * - * export const { auth, signIn, signOut, store } = convexAuth({ + * export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ * providers: [], * }); * ``` diff --git a/src/server/types.ts b/src/server/types.ts index d830225..0b32c1a 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -83,7 +83,7 @@ export type ConvexAuthConfig = { * import GitHub from "@auth/core/providers/github"; * import { convexAuth } from "@convex-dev/auth/server"; * - * export const { auth, signIn, signOut, store } = convexAuth({ + * export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ * providers: [GitHub], * callbacks: { * async redirect({ redirectTo }) { diff --git a/test-router/convex/auth.ts b/test-router/convex/auth.ts index 9448401..796d290 100644 --- a/test-router/convex/auth.ts +++ b/test-router/convex/auth.ts @@ -1,6 +1,6 @@ import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [GitHub], }); diff --git a/test/convex/auth.ts b/test/convex/auth.ts index eab2bc1..fbc4620 100644 --- a/test/convex/auth.ts +++ b/test/convex/auth.ts @@ -15,7 +15,7 @@ import { ResendOTPPasswordReset } from "./passwordReset/ResendOTPPasswordReset"; import { FakePhone } from "./otp/FakePhone"; import { DataModel } from "./_generated/dataModel.js"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ // !publish: remove FakePhone, From 4f4a69f4e38471c27c465031c9a7707ccb4b1881 Mon Sep 17 00:00:00 2001 From: Christian Wyglendowski Date: Tue, 10 Dec 2024 15:46:00 -0500 Subject: [PATCH 6/7] Doc updates after merge with main --- docs/pages/api_reference/nextjs/server.mdx | 10 +++++----- docs/pages/config/oauth/apple.mdx | 2 +- docs/pages/config/oauth/github.mdx | 2 +- docs/pages/config/oauth/google.mdx | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/pages/api_reference/nextjs/server.mdx b/docs/pages/api_reference/nextjs/server.mdx index dabb353..839aaa7 100644 --- a/docs/pages/api_reference/nextjs/server.mdx +++ b/docs/pages/api_reference/nextjs/server.mdx @@ -155,7 +155,7 @@ The token if the the client is authenticated, otherwise `undefined`.

Defined in

-[src/nextjs/server/index.tsx:83](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L83) +[src/nextjs/server/index.tsx:85](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L85) *** @@ -174,7 +174,7 @@ since they won't stop nested pages from rendering.

Defined in

-[src/nextjs/server/index.tsx:94](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L94) +[src/nextjs/server/index.tsx:96](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L96) *** @@ -213,7 +213,7 @@ export function convexAuthNextjsMiddleware(handler, options) {

Defined in

-[src/nextjs/server/index.tsx:113](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L113) +[src/nextjs/server/index.tsx:116](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L116) *** @@ -371,7 +371,7 @@ A Next.js middleware.

Defined in

-[src/nextjs/server/index.tsx:124](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L124) +[src/nextjs/server/index.tsx:127](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L127) *** @@ -435,7 +435,7 @@ The route path to redirect to.

Defined in

-[src/nextjs/server/index.tsx:272](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L272) +[src/nextjs/server/index.tsx:275](https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L275) *** diff --git a/docs/pages/config/oauth/apple.mdx b/docs/pages/config/oauth/apple.mdx index 2d20ce5..96f9e9b 100644 --- a/docs/pages/config/oauth/apple.mdx +++ b/docs/pages/config/oauth/apple.mdx @@ -181,7 +181,7 @@ written will be retained. import Apple from "@auth/core/providers/apple"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [ Apple({ profile: (appleInfo) => { diff --git a/docs/pages/config/oauth/github.mdx b/docs/pages/config/oauth/github.mdx index 6620748..8f9e271 100644 --- a/docs/pages/config/oauth/github.mdx +++ b/docs/pages/config/oauth/github.mdx @@ -90,7 +90,7 @@ environment variables above. import GitHub from "@auth/core/providers/github"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [GitHub], }); ``` diff --git a/docs/pages/config/oauth/google.mdx b/docs/pages/config/oauth/google.mdx index bf41b48..75a73a5 100644 --- a/docs/pages/config/oauth/google.mdx +++ b/docs/pages/config/oauth/google.mdx @@ -123,7 +123,7 @@ environment variables above. import Google from "@auth/core/providers/google"; import { convexAuth } from "@convex-dev/auth/server"; -export const { auth, signIn, signOut, store } = convexAuth({ +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Google], }); ``` From 935941bb152fe8c641bb53ac58ee29467f0aec45 Mon Sep 17 00:00:00 2001 From: Christian Wyglendowski Date: Tue, 10 Dec 2024 15:52:55 -0500 Subject: [PATCH 7/7] Enable better playwright test debug output Suggestion from review. --- test-nextjs/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-nextjs/playwright.config.ts b/test-nextjs/playwright.config.ts index 7e139f3..aa24e2c 100644 --- a/test-nextjs/playwright.config.ts +++ b/test-nextjs/playwright.config.ts @@ -77,7 +77,7 @@ export default defineConfig({ : "npm run dev:frontend", url: "http://127.0.0.1:3000", reuseExistingServer: !process.env.CI, - stdout: "ignore", // Set to "pipe" if you're debugging a failing test. + stdout: "pipe", stderr: "pipe", }, });