diff --git a/package-lock.json b/package-lock.json
index 9238a7f..060cb30 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,9 +16,11 @@
"clsx": "^2.1.1",
"lucide-react": "^0.503.0",
"next": "15.3.1",
+ "next-auth": "^5.0.0-beta.27",
"next-themes": "^0.4.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "simple-icons": "^14.12.3",
"tailwind-merge": "^3.2.0"
},
"devDependencies": {
@@ -47,6 +49,35 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@auth/core": {
+ "version": "0.39.0",
+ "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.39.0.tgz",
+ "integrity": "sha512-jusviw/sUSfAh6S/wjY5tRmJOq0Itd3ImF+c/b4HB9DfmfChtcfVJTNJeqCeExeCG8oh4PBKRsMQJsn2W6NhFQ==",
+ "license": "ISC",
+ "dependencies": {
+ "@panva/hkdf": "^1.2.1",
+ "jose": "^6.0.6",
+ "oauth4webapi": "^3.3.0",
+ "preact": "10.24.3",
+ "preact-render-to-string": "6.5.11"
+ },
+ "peerDependencies": {
+ "@simplewebauthn/browser": "^9.0.1",
+ "@simplewebauthn/server": "^9.0.2",
+ "nodemailer": "^6.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@simplewebauthn/browser": {
+ "optional": true
+ },
+ "@simplewebauthn/server": {
+ "optional": true
+ },
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@emnapi/core": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz",
@@ -904,6 +935,15 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@panva/hkdf": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
+ "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/@radix-ui/primitive": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
@@ -4498,6 +4538,15 @@
"jiti": "lib/jiti-cli.mjs"
}
},
+ "node_modules/jose": {
+ "version": "6.0.10",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-6.0.10.tgz",
+ "integrity": "sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -5055,6 +5104,33 @@
}
}
},
+ "node_modules/next-auth": {
+ "version": "5.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.27.tgz",
+ "integrity": "sha512-/QtP9C0C99YpEuBEJqMaDXH3ISWMgObQalwVZEoC7sskaIPhv5fQl6fXS/rXJQKqLY6MNJ42rqjqmRdoXZH2EQ==",
+ "license": "ISC",
+ "dependencies": {
+ "@auth/core": "0.39.0"
+ },
+ "peerDependencies": {
+ "@simplewebauthn/browser": "^9.0.1",
+ "@simplewebauthn/server": "^9.0.2",
+ "next": "^14.0.0-0 || ^15.0.0-0",
+ "nodemailer": "^6.6.5",
+ "react": "^18.2.0 || ^19.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@simplewebauthn/browser": {
+ "optional": true
+ },
+ "@simplewebauthn/server": {
+ "optional": true
+ },
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/next-themes": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
@@ -5093,6 +5169,15 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/oauth4webapi": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.0.tgz",
+ "integrity": "sha512-DF3mLWNuxPkxJkHmWxbSFz4aE5CjWOsm465VBfBdWzmzX4Mg3vF8icxK+iKqfdWrIumBJ2TaoNQWx+SQc2bsPQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -5382,6 +5467,25 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/preact": {
+ "version": "10.24.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
+ "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/preact-render-to-string": {
+ "version": "6.5.11",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz",
+ "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "preact": ">=10"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -5915,6 +6019,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/simple-icons": {
+ "version": "14.12.3",
+ "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-14.12.3.tgz",
+ "integrity": "sha512-P85Pqak4picfTzdujmGL7+pFfsd32K/tDjHPQ8vvJcr2Xk380A9kBVIW5QH86qWqa+YJgFa5huLcUuwmW+YBPQ==",
+ "license": "CC0-1.0",
+ "engines": {
+ "node": ">=0.12.18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/simple-icons"
+ }
+ },
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
diff --git a/package.json b/package.json
index 30b4bbb..9a22924 100644
--- a/package.json
+++ b/package.json
@@ -17,9 +17,11 @@
"clsx": "^2.1.1",
"lucide-react": "^0.503.0",
"next": "15.3.1",
+ "next-auth": "^5.0.0-beta.27",
"next-themes": "^0.4.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "simple-icons": "^14.12.3",
"tailwind-merge": "^3.2.0"
},
"devDependencies": {
diff --git a/src/app/api/auth/callback/github/route.ts b/src/app/api/auth/callback/github/route.ts
new file mode 100644
index 0000000..0cf1408
--- /dev/null
+++ b/src/app/api/auth/callback/github/route.ts
@@ -0,0 +1,2 @@
+import { handlers } from "@/auth" // Referring to the auth.ts we just created
+export const { GET, POST } = handlers
\ No newline at end of file
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
new file mode 100644
index 0000000..6d70784
--- /dev/null
+++ b/src/app/login/page.tsx
@@ -0,0 +1,12 @@
+import LoginForm from "@/components/login/login-form";
+import { Suspense } from "react";
+
+export default function LoginPage(){
+ return (
+
+ By clicking continue, you agree to our Terms of Service and Privacy Policy. +
+