diff --git a/packages/auth-nextjs/package.json b/packages/auth-nextjs/package.json index d1af2e586..2bf74604f 100644 --- a/packages/auth-nextjs/package.json +++ b/packages/auth-nextjs/package.json @@ -1,11 +1,11 @@ { - "name": "@edgedb/auth-nextjs", - "description": "Helper library to integrate the EdgeDB Auth extension with Next.js", + "name": "@gel/auth-nextjs", + "description": "Helper library to integrate the Gel Auth extension with Next.js", "version": "0.3.2", - "author": "EdgeDB ", + "author": "Gel ", "repository": { "type": "git", - "url": "https://github.com/edgedb/edgedb-js.git", + "url": "https://github.com/geldata/gel-js.git", "directory": "packages/auth-nextjs" }, "license": "Apache-2.0", @@ -28,18 +28,18 @@ "@repo/tsconfig": "*", "@types/node": "^20.12.13", "@types/react": "npm:types-react@rc", - "edgedb": "*", + "gel": "*", "next": "15.0.3", "react": "19.0.0-rc-b01722d5-20241114", "typescript": "^5.5.2" }, "peerDependencies": { - "edgedb": "^1.3.6", + "gel": "^1.3.6", "next": ">=13.5.6 <16.0.0", "react": "^18.2.0 || ^19.0" }, "dependencies": { - "@edgedb/auth-core": "0.2.1" + "@gel/auth-core": "0.2.1" }, "overrides": { "@types/react": "npm:types-react@rc" diff --git a/packages/auth-nextjs/readme.md b/packages/auth-nextjs/readme.md index 87a9a01c5..110ce168d 100644 --- a/packages/auth-nextjs/readme.md +++ b/packages/auth-nextjs/readme.md @@ -1,21 +1,22 @@ -# @edgedb/auth-nextjs: Helper library to integrate the EdgeDB Auth extension with Next.js +# @gel/auth-nextjs: Helper library to integrate the Gel Auth extension with Next.js > Warning: This library is still in an alpha state, and so, bugs are likely and the api's should be considered unstable and may change in future releases. ### Setup **Prerequisites**: + - Node v18+ - **Note**: Due to using the `crypto` global, you will need to start Node with `--experimental-global-webcrypto`. You can add this option to your `NODE_OPTIONS` environment variable, like `NODE_OPTIONS='--experimental-global-webcrypto'` in the appropriate `.env` file. -- Before adding EdgeDB auth to your Next.js app, you will first need to enable the `auth` extension in your EdgeDB schema, and have configured the extension with some providers. Refer to the auth extension docs for details on how to do this. +- Before adding Gel auth to your Next.js app, you will first need to enable the `auth` extension in your Gel schema, and have configured the extension with some providers. Refer to the auth extension docs for details on how to do this. -1. Initialize the auth helper by passing an EdgeDB `Client` object to `createAuth()`, along with some configuration options. This will return a `NextAppAuth` object which you can use across your app. Similarly to the `Client` it's recommended to export this auth object from some root configuration file in your app. +1. Initialize the auth helper by passing an Gel `Client` object to `createAuth()`, along with some configuration options. This will return a `NextAppAuth` object which you can use across your app. Similarly to the `Client` it's recommended to export this auth object from some root configuration file in your app. ```ts - // edgedb.ts + // gel.ts - import { createClient } from "edgedb"; - import createAuth from "@edgedb/auth-nextjs/app"; + import { createClient } from "gel"; + import createAuth from "@gel/auth-nextjs/app"; export const client = createClient(); @@ -28,8 +29,8 @@ - `baseUrl: string`, _required_, The url of your application; needed for various auth flows (eg. OAuth) to redirect back to. - `authRoutesPath?: string`, The path to the auth route handlers, defaults to `'auth'`, see below for more details. - - `authCookieName?: string`, The name of the cookie where the auth token will be stored, defaults to `'edgedb-session'`. - - `pkceVerifierCookieName?: string`: The name of the cookie where the verifier for the PKCE flow will be stored, defaults to `'edgedb-pkce-verifier'` + - `authCookieName?: string`, The name of the cookie where the auth token will be stored, defaults to `'gel-session'`. + - `pkceVerifierCookieName?: string`: The name of the cookie where the verifier for the PKCE flow will be stored, defaults to `'gel-pkce-verifier'` - `passwordResetPath?: string`: The path relative to the `baseUrl` of the the password reset page; needed if you want to enable password reset emails in your app. - `magicLinkFailurePath?: string`: The path relative to the `baseUrl` of the page we should redirect users to if there is an error when trying to sign in with a magic link. The page will get an `error` search parameter attached with an error message. This property is required if you use the Magic Link authentication feature. @@ -39,7 +40,7 @@ // app/auth/[...auth]/route.ts import { redirect } from "next/navigation"; - import { auth } from "@/edgedb"; + import { auth } from "@/gel"; const { GET, POST } = auth.createAuthRouteHandlers({ onOAuthCallback({ error, tokenData, isSignUp }) { @@ -68,7 +69,7 @@ By default the handlers expect to exist under the `/auth` path in your app, however if you want to place them elsewhere, you will also need to configure the `authRoutesPath` option of `createAuth` to match. -3. Now we just need to setup the UI to allow your users to sign in/up, etc. The easiest way to get started is to use the EdgeDB Auth's builtin UI. Or alternatively you can implement your own custom UI. +3. Now we just need to setup the UI to allow your users to sign in/up, etc. The easiest way to get started is to use the Gel Auth's builtin UI. Or alternatively you can implement your own custom UI. **Builtin UI** @@ -97,7 +98,7 @@ Now you have auth all configured and user's can signin/signup/etc. you can use the `auth.getSession()` method in your app pages to retrieve an `AuthSession` object. This session object allows you to check if the user is currently logged in with the `isSignedIn` method, and also provides a `Client` object automatically configured with the `ext::auth::client_token` global, so you can run queries using the `ext::auth::ClientTokenIdentity` of the currently signed in user. ```ts -import { auth } from "@/edgedb"; +import { auth } from "@/gel"; export default async function Home() { const session = await auth.getSession(); diff --git a/packages/auth-nextjs/src/app/client.ts b/packages/auth-nextjs/src/app/client.ts index 97c42e64a..12e350ea1 100644 --- a/packages/auth-nextjs/src/app/client.ts +++ b/packages/auth-nextjs/src/app/client.ts @@ -4,7 +4,7 @@ import { type NextAuthOptions, } from "../shared.client"; -export * from "@edgedb/auth-core/errors"; +export * from "@gel/auth-core/errors"; export { type NextAuthOptions, type BuiltinProviderNames }; export default function createNextAppClientAuth(options: NextAuthOptions) { diff --git a/packages/auth-nextjs/src/app/index.ts b/packages/auth-nextjs/src/app/index.ts index 45dad82ef..97d8e6f79 100644 --- a/packages/auth-nextjs/src/app/index.ts +++ b/packages/auth-nextjs/src/app/index.ts @@ -3,8 +3,8 @@ import { ConfigurationError, PKCEError, InvalidDataError, -} from "@edgedb/auth-core"; -import type { Client } from "edgedb"; +} from "@gel/auth-core"; +import type { Client } from "gel"; import { cookies } from "next/headers"; import { cache } from "react"; @@ -17,7 +17,7 @@ import { _extractParams, } from "../shared"; -export * from "@edgedb/auth-core/errors"; +export * from "@gel/auth-core/errors"; export { NextAuthSession, type NextAuthOptions, @@ -31,15 +31,16 @@ export class NextAppAuth extends NextAuth { const cookieStore = await cookies(); return new NextAuthSession( this.client, - cookieStore.get(this.options.authCookieName)?.value.split(";")[0] ?? null, + cookieStore.get(this.options.authCookieName)?.value.split(";")[0] || + cookieStore.get("edgedb-session")?.value.split(";")[0] || + null, ); }); createServerActions() { return { signout: async () => { - const cookieStore = await cookies(); - cookieStore.delete(this.options.authCookieName); + this.deleteAuthCookie(); }, emailPasswordSignIn: async ( data: FormData | { email: string; password: string }, @@ -101,9 +102,9 @@ export class NextAppAuth extends NextAuth { data: FormData | { reset_token: string; password: string }, ) => { const cookieStore = await cookies(); - const verifier = cookieStore.get( - this.options.pkceVerifierCookieName, - )?.value; + const verifier = + cookieStore.get(this.options.pkceVerifierCookieName)?.value || + cookieStore.get("edgedb-pkce-verifier")?.value; if (!verifier) { throw new PKCEError("no pkce verifier cookie found"); } @@ -116,7 +117,7 @@ export class NextAppAuth extends NextAuth { await this.core ).resetPasswordWithResetToken(resetToken, verifier, password); await this.setAuthCookie(tokenData.auth_token); - cookieStore.delete(this.options.pkceVerifierCookieName); + this.deleteVerifierCookie(); return tokenData; }, emailPasswordResendVerificationEmail: async ( diff --git a/packages/auth-nextjs/src/pages/client.ts b/packages/auth-nextjs/src/pages/client.ts index 2cd8a6557..3e334a42c 100644 --- a/packages/auth-nextjs/src/pages/client.ts +++ b/packages/auth-nextjs/src/pages/client.ts @@ -4,9 +4,9 @@ import { NextAuthHelpers, type NextAuthOptions, } from "../shared.client"; -import { errorMapping } from "@edgedb/auth-core/utils"; +import { errorMapping } from "@gel/auth-core/utils"; -export * from "@edgedb/auth-core/errors"; +export * from "@gel/auth-core/errors"; export { type NextAuthOptions, type BuiltinProviderNames }; export default function createNextPagesClientAuth(options: NextAuthOptions) { diff --git a/packages/auth-nextjs/src/pages/server.ts b/packages/auth-nextjs/src/pages/server.ts index f044850e8..6f47f5436 100644 --- a/packages/auth-nextjs/src/pages/server.ts +++ b/packages/auth-nextjs/src/pages/server.ts @@ -1,5 +1,5 @@ -import { type Client } from "edgedb"; -import { type TokenData } from "@edgedb/auth-core"; +import { type Client } from "gel"; +import { type TokenData } from "@gel/auth-core"; import { type BuiltinProviderNames, type CreateAuthRouteHandlers, @@ -8,7 +8,7 @@ import { NextAuthSession, } from "../shared"; -export * from "@edgedb/auth-core/errors"; +export * from "@gel/auth-core/errors"; export { NextAuthSession, type NextAuthOptions, @@ -32,7 +32,9 @@ export class NextPagesAuth extends NextAuth { sessionCache.get(req) ?? new NextAuthSession( this.client, - req.cookies[this.options.authCookieName]?.split(";")[0] ?? null, + req.cookies[this.options.authCookieName]?.split(";")[0] || + req.cookies["edgedb-session"]?.split(";")[0] || + null, ); sessionCache.set(req, session); return session; diff --git a/packages/auth-nextjs/src/shared.client.ts b/packages/auth-nextjs/src/shared.client.ts index 9a3f8d881..09112b6e5 100644 --- a/packages/auth-nextjs/src/shared.client.ts +++ b/packages/auth-nextjs/src/shared.client.ts @@ -1,10 +1,10 @@ import { type BuiltinOAuthProviderNames, type emailPasswordProviderName, -} from "@edgedb/auth-core"; -import { WebAuthnClient } from "@edgedb/auth-core/webauthn"; +} from "@gel/auth-core"; +import { WebAuthnClient } from "@gel/auth-core/webauthn"; -export * as webauthn from "@edgedb/auth-core/webauthn"; +export * as webauthn from "@gel/auth-core/webauthn"; export type BuiltinProviderNames = | BuiltinOAuthProviderNames @@ -33,9 +33,9 @@ export abstract class NextAuthHelpers { this.options = { baseUrl: options.baseUrl.replace(/\/$/, ""), authRoutesPath: options.authRoutesPath?.replace(/^\/|\/$/g, "") ?? "auth", - authCookieName: options.authCookieName ?? "edgedb-session", + authCookieName: options.authCookieName ?? "gel-session", pkceVerifierCookieName: - options.pkceVerifierCookieName ?? "edgedb-pkce-verifier", + options.pkceVerifierCookieName ?? "gel-pkce-verifier", passwordResetPath: options.passwordResetPath, magicLinkFailurePath: options.magicLinkFailurePath, }; diff --git a/packages/auth-nextjs/src/shared.ts b/packages/auth-nextjs/src/shared.ts index e085bcf07..61e05e7e8 100644 --- a/packages/auth-nextjs/src/shared.ts +++ b/packages/auth-nextjs/src/shared.ts @@ -1,4 +1,4 @@ -import { type Client } from "edgedb"; +import { type Client } from "gel"; import { Auth, type BuiltinOAuthProviderNames, @@ -6,10 +6,10 @@ import { ConfigurationError, InvalidDataError, PKCEError, - EdgeDBAuthError, + GelAuthError, OAuthProviderFailureError, type SignupResponse, -} from "@edgedb/auth-core"; +} from "@gel/auth-core"; import { type BuiltinProviderNames, @@ -125,11 +125,6 @@ export abstract class NextAuth extends NextAuthHelpers { }); } - async deleteVerifierCookie() { - const cookieStore = await cookies(); - cookieStore.delete(this.options.pkceVerifierCookieName); - } - async setAuthCookie(token: string) { const cookieStore = await cookies(); const expirationDate = Auth.getTokenExpiration(token); @@ -144,6 +139,18 @@ export abstract class NextAuth extends NextAuthHelpers { }); } + async deleteVerifierCookie() { + const cookieStore = await cookies(); + cookieStore.delete(this.options.pkceVerifierCookieName); + cookieStore.delete("edgedb-pkce-verifier"); + } + + async deleteAuthCookie() { + const cookieStore = await cookies(); + cookieStore.delete(this.options.authCookieName); + cookieStore.delete("edgedb-session"); + } + public oAuth = { /** * Start the OAuth flow by getting the OAuth configuration from the request @@ -261,6 +268,10 @@ export abstract class NextAuth extends NextAuthHelpers { req: NextRequest, ctx: { params: Promise<{ auth: string[] }> }, ) => { + const verifier = + req.cookies.get(this.options.pkceVerifierCookieName)?.value || + req.cookies.get("edgedb-pkce-verifier")?.value; + const params = await ctx.params; switch (params.auth.join("/")) { case "oauth": { @@ -292,9 +303,6 @@ export abstract class NextAuth extends NextAuthHelpers { const code = req.nextUrl.searchParams.get("code"); const isSignUp = req.nextUrl.searchParams.get("isSignUp") === "true"; - const verifier = req.cookies.get( - this.options.pkceVerifierCookieName, - )?.value; if (!code) { return onOAuthCallback( { @@ -345,9 +353,6 @@ export abstract class NextAuth extends NextAuthHelpers { } const verificationToken = req.nextUrl.searchParams.get("verification_token"); - const verifier = req.cookies.get( - this.options.pkceVerifierCookieName, - )?.value; if (!verificationToken) { return onEmailVerify( { @@ -414,9 +419,6 @@ export abstract class NextAuth extends NextAuthHelpers { } const verificationToken = req.nextUrl.searchParams.get("verification_token"); - const verifier = req.cookies.get( - this.options.pkceVerifierCookieName, - )?.value; if (!verificationToken) { return onEmailVerify( { @@ -474,9 +476,6 @@ export abstract class NextAuth extends NextAuthHelpers { const code = req.nextUrl.searchParams.get("code"); const isSignUp = req.nextUrl.searchParams.get("isSignUp") === "true"; - const verifier = req.cookies.get( - this.options.pkceVerifierCookieName, - )?.value; if (!code) { return onMagicLinkCallback( { @@ -527,7 +526,7 @@ export abstract class NextAuth extends NextAuthHelpers { const desc = req.nextUrl.searchParams.get("error_description"); return onBuiltinUICallback( { - error: new EdgeDBAuthError(error + (desc ? `: ${desc}` : "")), + error: new GelAuthError(error + (desc ? `: ${desc}` : "")), }, req, ); @@ -556,9 +555,6 @@ export abstract class NextAuth extends NextAuthHelpers { req, ); } - const verifier = req.cookies.get( - this.options.pkceVerifierCookieName, - )?.value; if (!verifier) { return onBuiltinUICallback( { @@ -614,8 +610,7 @@ export abstract class NextAuth extends NextAuthHelpers { `'onSignout' auth route handler not configured`, ); } - const cookieStore = await cookies(); - cookieStore.delete(this.options.authCookieName); + this.deleteAuthCookie(); return onSignout(req); } default: @@ -747,9 +742,9 @@ export abstract class NextAuth extends NextAuthHelpers { } let tokenData: TokenData; try { - const verifier = req.cookies.get( - this.options.pkceVerifierCookieName, - )?.value; + const verifier = + req.cookies.get(this.options.pkceVerifierCookieName)?.value || + req.cookies.get("edgedb-pkce-verifier")?.value; if (!verifier) { throw new PKCEError("no pkce verifier cookie found"); } @@ -1034,7 +1029,7 @@ function _wrapResponse(res: Promise | undefined, isAction: boolean) { function _wrapError(err: Error) { return { _error: { - type: err instanceof EdgeDBAuthError ? err.type : null, + type: err instanceof GelAuthError ? err.type : null, message: err instanceof Error ? err.message : String(err), }, };