From 08c3dab24acb5855ec66c5b1f68776fafe195d16 Mon Sep 17 00:00:00 2001 From: Security2431 Date: Thu, 4 Jan 2024 09:33:22 +0200 Subject: [PATCH] fix: credential auth --- apps/nextjs/package.json | 1 + .../src/app/_components/credential-auth.tsx | 69 ++++++++ apps/nextjs/src/app/page.tsx | 3 + packages/api/src/router/user.ts | 5 + packages/auth/index.ts | 150 +++++++++++++++++- pnpm-lock.yaml | 136 ++++++++++++++++ 6 files changed, 357 insertions(+), 7 deletions(-) create mode 100644 apps/nextjs/src/app/_components/credential-auth.tsx diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index b9cc2bda..5ca69963 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -25,6 +25,7 @@ "@trpc/next": "^10.40.0", "@trpc/react-query": "^10.40.0", "@trpc/server": "^10.40.0", + "argon2": "^0.31.2", "classnames": "^2.3.2", "date-fns": "^2.30.0", "emoji-picker-react": "^4.5.7", diff --git a/apps/nextjs/src/app/_components/credential-auth.tsx b/apps/nextjs/src/app/_components/credential-auth.tsx new file mode 100644 index 00000000..c5289bc1 --- /dev/null +++ b/apps/nextjs/src/app/_components/credential-auth.tsx @@ -0,0 +1,69 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { signIn } from "next-auth/react"; +import type { SubmitHandler } from "react-hook-form"; +import { FormProvider, useForm } from "react-hook-form"; +import { toast } from "react-toastify"; +import * as z from "zod"; + +import Button from "./button"; +import Field from "./form/Field"; + +/* Local constants & types +============================================================================= */ +export type FormData = z.infer; + +const schemaValidation = z.object({ + email: z.string(), + password: z.string(), +}); + +const CredentialAuth = () => { + const router = useRouter(); + const methods = useForm({ + resolver: zodResolver(schemaValidation), + defaultValues: { + email: "", + password: "", + }, + }); + + const onSubmit: SubmitHandler = async (data: FormData) => { + try { + const response = await signIn("credentials", { + ...data, + redirect: false, + }); + + console.log({ response }); + if (!response?.error) { + router.push("/workspaces"); + router.refresh(); + } + } catch (error) { + console.error(error); + toast.error("Invalid email or password"); + } + }; + + return ( +
+ + + + + + +
+ ); +}; + +export default CredentialAuth; diff --git a/apps/nextjs/src/app/page.tsx b/apps/nextjs/src/app/page.tsx index ba97e3ff..6f2d5978 100644 --- a/apps/nextjs/src/app/page.tsx +++ b/apps/nextjs/src/app/page.tsx @@ -3,6 +3,7 @@ import { redirect } from "next/navigation"; import { auth } from "@acme/auth"; import { AuthShowcase } from "./_components/auth-showcase"; +import CredentialAuth from "./_components/credential-auth"; import Heading from "./_components/heading"; import { Meteors } from "./_components/meteors"; import routes from "./_lib/routes"; @@ -27,6 +28,8 @@ export default async function HomePage() { with 2day.report!

+ +

{ +// for (let key of keys) { +// delete user[key]; +// } +// return user; +// }; + +const validatePassword = async ( + plainPassword: string, + hashedPassword?: string | null, +) => { + if (!hashedPassword) { + return false; + } + + return await verify(hashedPassword, plainPassword); +}; + export const { handlers: { GET, POST }, auth, @@ -42,15 +63,130 @@ export const { clientSecret: env.GITHUB_CLIENT_SECRET, allowDangerousEmailAccountLinking: true, }), - ], - callbacks: { - session: ({ session, user }) => ({ - ...session, - user: { - ...session.user, - id: user.id, + Credentials({ + name: "Credentials", + credentials: { + email: { + label: "Email: ", + type: "text", + }, + password: { + label: "Password: ", + type: "password", + }, }, + + async authorize(credentials) { + const { email, password } = credentials as { + email: string; + password: string; + }; + + const user = await prisma.user.findFirst({ + where: { + email: { + equals: email, + mode: "insensitive", + }, + }, + }); + + const isValidPassword = await validatePassword( + password, + user?.password, + ); + + if (!user || !isValidPassword) { + throw new Error("Invalid email or password"); + } + + // TODO: exclude password field + return user; + }, + + // This is where you need to retrieve user data + // to verify with credentials + // await new Promise((resolve) => setTimeout(resolve, 1000)); + + // if ( + // credentials.email === user.email && + // credentials.password === user.password + // ) { + // return user; + // } + + // return null; + // }, }), + ], + callbacks: { + jwt({ token, user, session }) { + console.log( + "jwt-------------------------------------------------------", + session, + token, + user, + ); + + // if (trigger === "update" && session?.name) { + // token.name = session.name; + // } + + if (user) { + return { + ...token, + id: user.id, + email: user.email, + }; + } + + return token; + }, + // async signIn({ user, account, profile, email, credentials }) { + // if (credentials) { + // return true; + // } + + // console.log("email", email); + // console.log("profile", profile); + // console.log("account", account); + // console.log("user", user); + + // const dbUser = await prisma.user.upsert({ + // where: { email: user.email! }, + // update: { + // name: user.name!, + // image: user.image, + // }, + // create: { + // name: user.name!, + // email: user.email!, + // image: user.image, + // password: user.name!, + // }, + // }); + // // add the userId to the session object + // // user.role = dbUser.role; + // user.id = dbUser.id; + + // return true; + // }, + session: ({ session, token, user }) => { + console.log( + "session-------------------------------------------------------", + session, + token, + user, + ); + return { + ...session, + user: { + ...session.user, + id: token.id, + name: token.name, + }, + }; + }, // @TODO - if you wanna have auth on the edge // jwt: ({ token, profile }) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3a1c6163..d078f10c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -174,6 +174,9 @@ importers: '@trpc/server': specifier: ^10.40.0 version: 10.40.0 + argon2: + specifier: ^0.31.2 + version: 0.31.2 classnames: specifier: ^2.3.2 version: 2.3.2 @@ -2676,6 +2679,24 @@ packages: read-yaml-file: 1.1.0 dev: false + /@mapbox/node-pre-gyp@1.0.11: + resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} + hasBin: true + dependencies: + detect-libc: 2.0.2 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.6.11 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.5.4 + tar: 6.1.14 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@next/env@13.5.4: resolution: {integrity: sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ==} dev: false @@ -2804,6 +2825,11 @@ packages: resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==} dev: false + /@phc/format@1.0.0: + resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} + engines: {node: '>=10'} + dev: false + /@prisma/client@5.4.2(prisma@5.4.2): resolution: {integrity: sha512-2xsPaz4EaMKj1WS9iW6MlPhmbqtBsXAOeVttSePp8vTFTtvzh2hZbDgswwBdSCgPzmmwF+tLB259QzggvCmJqA==} engines: {node: '>=16.13'} @@ -3787,6 +3813,10 @@ packages: resolution: {integrity: sha512-hb9QhOg5MGmpVkFcoZ9XJMe1em5gd0e2eqqjK87O1dwULedXsnY/Zg/Ju6lcohA+t6jVkmKpe7I1etqhvdRdrQ==} engines: {node: '>=10.0.0'} + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: false + /abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -3949,6 +3979,18 @@ packages: resolution: {integrity: sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==} dev: false + /aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: false + + /are-we-there-yet@2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: false + /arg@4.1.0: resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==} dev: false @@ -3956,6 +3998,19 @@ packages: /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + /argon2@0.31.2: + resolution: {integrity: sha512-QSnJ8By5Mth60IEte45w9Y7v6bWcQw3YhRtJKKN8oNCxnTLDiv/AXXkDPf2srTMfxFVn3QJdVv2nhXESsUa+Yg==} + engines: {node: '>=14.0.0'} + requiresBuild: true + dependencies: + '@mapbox/node-pre-gyp': 1.0.11 + '@phc/format': 1.0.0 + node-addon-api: 7.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -4709,6 +4764,11 @@ packages: simple-swizzle: 0.2.2 dev: false + /color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: false + /color@4.2.3: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} @@ -4812,6 +4872,10 @@ packages: - supports-color dev: false + /console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: false + /constant-case@2.0.0: resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} dependencies: @@ -5130,6 +5194,10 @@ packages: engines: {node: '>=0.4.0'} dev: false + /delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: false + /denodeify@1.2.1: resolution: {integrity: sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==} dev: false @@ -5165,6 +5233,12 @@ packages: /detect-libc@1.0.3: resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} engines: {node: '>=0.10'} + hasBin: true + dev: false + + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} dev: false /devlop@1.1.0: @@ -6249,6 +6323,21 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: false + /gauge@3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -6529,6 +6618,10 @@ packages: has-symbols: 1.0.3 dev: false + /has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: false + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -7639,6 +7732,13 @@ packages: semver: 5.7.1 dev: false + /make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.1 + dev: false + /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} dev: false @@ -8504,6 +8604,7 @@ packages: /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} + hasBin: true dev: false /ms@2.0.0: @@ -8671,6 +8772,10 @@ packages: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} dev: false + /node-addon-api@7.0.0: + resolution: {integrity: sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==} + dev: false + /node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} @@ -8736,6 +8841,14 @@ packages: engines: {node: '>=0.12.0'} dev: false + /nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: false + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -8773,6 +8886,15 @@ packages: path-key: 3.1.1 dev: false + /npmlog@5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: false + /nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} dev: false @@ -10147,6 +10269,7 @@ packages: /rimraf@2.4.5: resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} + hasBin: true requiresBuild: true dependencies: glob: 6.0.4 @@ -10155,18 +10278,21 @@ packages: /rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + hasBin: true dependencies: glob: 7.2.3 dev: false /rimraf@2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true dependencies: glob: 7.2.3 dev: false /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true dependencies: glob: 7.2.3 @@ -10273,6 +10399,7 @@ packages: /semver@5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true dev: false /semver@6.3.0: @@ -10285,11 +10412,13 @@ packages: /semver@7.3.2: resolution: {integrity: sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==} engines: {node: '>=10'} + hasBin: true dev: false /semver@7.5.3: resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==} engines: {node: '>=10'} + hasBin: true dependencies: lru-cache: 6.0.0 dev: false @@ -10297,6 +10426,7 @@ packages: /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} + hasBin: true dependencies: lru-cache: 6.0.0 @@ -11567,6 +11697,12 @@ packages: dependencies: isexe: 2.0.0 + /wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 + dev: false + /wonka@4.0.15: resolution: {integrity: sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==} dev: false