diff --git a/.env.example b/.env.example index 643a5cb1e..a703b1098 100644 --- a/.env.example +++ b/.env.example @@ -2,17 +2,15 @@ ## Then get your OpenAI API Key here: https://platform.openai.com/account/api-keys OPENAI_API_KEY=XXXXXXXX -## Generate a random secret: https://generate-secret.vercel.app/32 -NEXTAUTH_SECRET=XXXXXXXX - -## Only required for localhost -NEXTAUTH_URL=http://localhost:3000 - +## Generate a random secret: https://generate-secret.vercel.app/32 or `openssl rand -base64 32` +AUTH_SECRET=XXXXXXXX ## Create a GitHub OAuth app here: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app AUTH_GITHUB_ID=XXXXXXXX AUTH_GITHUB_SECRET=XXXXXXXX +## Support OAuth login on preview deployments, see: https://authjs.dev/guides/basics/deployment#securing-a-preview-deployment +AUTH_REDIRECT_PROXY_URL=https://auth.example.com/api/auth -# instructions to create kv database here: https://vercel.com/docs/storage/vercel-kv/quickstart and +# Instructions to create kv database here: https://vercel.com/docs/storage/vercel-kv/quickstart and KV_URL=XXXXXXXX KV_REST_API_URL=XXXXXXXX KV_REST_API_TOKEN=XXXXXXXX diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index 35e97192e..883210bb2 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -1 +1,2 @@ export { GET, POST } from '@/auth' +export const runtime = 'edge' diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index 594925c3e..02e7571db 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -16,9 +16,9 @@ const openai = new OpenAIApi(configuration) export async function POST(req: Request) { const json = await req.json() const { messages, previewToken } = json - const session = await auth() + const userId = (await auth())?.user.id - if (session == null) { + if (!userId) { return new Response('Unauthorized', { status: 401 }) @@ -38,31 +38,28 @@ export async function POST(req: Request) { const stream = OpenAIStream(res, { async onCompletion(completion) { const title = json.messages[0].content.substring(0, 100) - const userId = session?.user?.id - if (userId) { - const id = json.id ?? nanoid() - const createdAt = Date.now() - const path = `/chat/${id}` - const payload = { - id, - title, - userId, - createdAt, - path, - messages: [ - ...messages, - { - content: completion, - role: 'assistant' - } - ] - } - await kv.hmset(`chat:${id}`, payload) - await kv.zadd(`user:chat:${userId}`, { - score: createdAt, - member: `chat:${id}` - }) + const id = json.id ?? nanoid() + const createdAt = Date.now() + const path = `/chat/${id}` + const payload = { + id, + title, + userId, + createdAt, + path, + messages: [ + ...messages, + { + content: completion, + role: 'assistant' + } + ] } + await kv.hmset(`chat:${id}`, payload) + await kv.zadd(`user:chat:${userId}`, { + score: createdAt, + member: `chat:${id}` + }) } }) diff --git a/auth.ts b/auth.ts index 4660cfb60..d272d78db 100644 --- a/auth.ts +++ b/auth.ts @@ -1,64 +1,35 @@ -import NextAuth from 'next-auth' +import NextAuth, { type DefaultSession } from 'next-auth' import GitHub from 'next-auth/providers/github' -import CredentialsProvider from 'next-auth/providers/credentials' +import { NextResponse } from 'next/server' -// We default to using GitHub for authentication for local development and production. -// On Preview deployments, we use a dummy credentials provider. This allows folks to easily -// test the app without having to create a custom GitHub OAuth app or change the callback URL -// just to test the application on previews. +declare module 'next-auth' { + interface Session { + user: { + /** The user's id. */ + id: string + } & DefaultSession['user'] + } +} -// We have a custom /sign-in page for non-preview environments. In preview environments, the user -// will be redirected to /api/auth/signin instead. export const { handlers: { GET, POST }, auth, CSRF_experimental - // @ts-ignore } = NextAuth({ - // @ts-ignore - providers: [ - process.env.VERCEL_ENV === 'preview' - ? CredentialsProvider({ - name: 'Credentials', - credentials: { - username: { - label: 'Username', - type: 'text', - placeholder: 'jsmith' - }, - password: { label: 'Password', type: 'password' } - }, - async authorize(credentials) { - return { - id: 1, - name: 'J Smith', - email: 'jsmith@example.com', - picture: 'https://i.pravatar.cc/150?u=jsmith@example.com' - } as any - } - }) - : GitHub - ], + providers: [GitHub], callbacks: { - // @ts-ignore - jwt: async ({ token, profile }) => { - if (profile?.id) { + jwt({ token, profile }) { + if (profile) { token.id = profile.id token.image = profile.picture } return token }, - // @ts-ignore authorized({ auth }) { return !!auth?.user - }, - trustHost: true + } }, - ...(process.env.VERCEL_ENV === 'preview' - ? {} - : { - pages: { - signIn: '/sign-in' - } - }) + pages: { + signIn: '/sign-in' + } }) diff --git a/middleware.ts b/middleware.ts index d70f75328..83a5d0843 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,5 +1,5 @@ export { auth as middleware } from './auth' export const config = { - matcher: ['/', '/api/chat'] + matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'] } diff --git a/next-auth.d.ts b/next-auth.d.ts deleted file mode 100644 index 918e14d8f..000000000 --- a/next-auth.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import NextAuth, { DefaultSession } from 'next-auth' - -declare module 'next-auth' { - /** - * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context - */ - interface Session { - user: { - /** The user's postal address. */ - id: string - } & DefaultSession['user'] - } -} diff --git a/package.json b/package.json index f42a41a58..2cad86033 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "focus-trap-react": "^10.1.1", "nanoid": "^4.0.2", "next": "13.4.7-canary.1", - "next-auth": "0.0.0-manual.e65faa1c", + "next-auth": "0.0.0-manual.83c4ebd1", "next-themes": "^0.2.1", "openai-edge": "^0.5.1", "react": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4325c0062..2ca8d29a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -60,8 +60,8 @@ dependencies: specifier: 13.4.7-canary.1 version: 13.4.7-canary.1(react-dom@18.2.0)(react@18.2.0) next-auth: - specifier: 0.0.0-manual.e65faa1c - version: 0.0.0-manual.e65faa1c(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0) + specifier: 0.0.0-manual.83c4ebd1 + version: 0.0.0-manual.83c4ebd1(next@13.4.7-canary.1)(react@18.2.0) next-themes: specifier: ^0.2.1 version: 0.2.1(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0) @@ -172,19 +172,6 @@ packages: preact-render-to-string: 5.2.3(preact@10.11.3) dev: false - /@auth/nextjs@0.0.0-manual.179c08d4(next@13.4.7-canary.1)(react@18.2.0): - resolution: {integrity: sha512-HVuDgb6xlYLV5mHTGc0Pycg8BlwtcvjvS+54QXEbOBpA5tulzKxAH8QlCoKj5R9XHW9hP9DiCnvXyVV9x2N+jA==} - peerDependencies: - next: ^13.4.6 - react: ^18.2.0 - dependencies: - '@auth/core': 0.0.0-manual.8fcd46b0 - next: 13.4.7-canary.1(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - transitivePeerDependencies: - - nodemailer - dev: false - /@babel/helper-string-parser@7.22.5: resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} @@ -3696,21 +3683,19 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /next-auth@0.0.0-manual.e65faa1c(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-I51GvhZhZEf/gzhiTKivYPAIyZ74sCF3YXAMMuZ/bjahybeehPEu7opcPEA+H0Uxrvmo2G8/BQ7mT+TiFdM9IQ==} + /next-auth@0.0.0-manual.83c4ebd1(next@13.4.7-canary.1)(react@18.2.0): + resolution: {integrity: sha512-6nUXtVrZqTWvVz2NhUB/xbMyzxUSQycQWOquACwdpk63AcnZ3g01v+W0UX9paqkGIdqLPtI/pL6rA2N+MT58SQ==} peerDependencies: - next: ^13.4.5 + next: ^13.4.6 nodemailer: ^6.6.5 - react: ^17.0.2 || ^18 - react-dom: ^17.0.2 || ^18 + react: ^18.2.0 peerDependenciesMeta: nodemailer: optional: true dependencies: - '@auth/nextjs': 0.0.0-manual.179c08d4(next@13.4.7-canary.1)(react@18.2.0) + '@auth/core': 0.0.0-manual.8fcd46b0 next: 13.4.7-canary.1(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) dev: false /next-themes@0.2.1(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0):