From 349c696cda29d78164906dd52a139c765907b9a5 Mon Sep 17 00:00:00 2001 From: pilcrowOnPaper <80624252+pilcrowOnPaper@users.noreply.github.com> Date: Fri, 15 Sep 2023 20:44:27 +0900 Subject: [PATCH] Move examples to its own repo (#1122) --- README.md | 4 +- .../email-verification-links/$express.md | 6 +- .../email-verification-links/$nextjs-app.md | 6 +- .../email-verification-links/$nextjs-pages.md | 6 +- .../email-verification-links/$nuxt.md | 6 +- .../email-verification-links/$sveltekit.md | 6 +- .../guidebook/github-oauth-native/electron.md | 6 +- .../guidebook/github-oauth-native/expo.md | 6 +- .../guidebook/github-oauth-native/tauri.md | 6 +- .../content/guidebook/github-oauth/$astro.md | 6 +- .../guidebook/github-oauth/$express.md | 6 +- .../guidebook/github-oauth/$nextjs-app.md | 6 +- .../guidebook/github-oauth/$nextjs-pages.md | 6 +- .../content/guidebook/github-oauth/$nuxt.md | 6 +- .../guidebook/github-oauth/$solidstart.md | 6 +- .../guidebook/github-oauth/$sveltekit.md | 6 +- .../content/guidebook/login-throttling.md | 4 +- .../guidebook/password-reset-link/$express.md | 6 +- .../password-reset-link/$nextjs-app.md | 6 +- .../password-reset-link/$nextjs-pages.md | 6 +- .../guidebook/password-reset-link/$nuxt.md | 6 +- .../password-reset-link/$sveltekit.md | 6 +- .../$astro.md | 6 +- .../$express.md | 6 +- .../$nextjs-app.md | 6 +- .../$nextjs-pages.md | 6 +- .../$nuxt.md | 6 +- .../$solidstart.md | 6 +- .../$sveltekit.md | 6 +- documentation/content/main/contributing.md | 6 +- documentation/src/layouts/BaseLayout.astro | 11 +- examples/astro/email-and-password/.gitignore | 23 - .../astro/email-and-password/.prettierignore | 2 - examples/astro/email-and-password/README.md | 19 - .../astro/email-and-password/astro.config.mjs | 11 - .../astro/email-and-password/package.json | 24 - .../email-and-password/public/favicon.svg | 9 - examples/astro/email-and-password/schema.sql | 28 - examples/astro/email-and-password/src/app.css | 10 - .../astro/email-and-password/src/env.d.ts | 16 - .../astro/email-and-password/src/lib/db.ts | 49 - .../astro/email-and-password/src/lib/email.ts | 16 - .../astro/email-and-password/src/lib/lucia.ts | 22 - .../astro/email-and-password/src/lib/token.ts | 112 - .../email-and-password/src/middleware.ts | 8 - .../src/pages/email-verification/[token].ts | 36 - .../src/pages/email-verification/index.astro | 45 - .../email-and-password/src/pages/index.astro | 27 - .../email-and-password/src/pages/login.astro | 86 - .../email-and-password/src/pages/logout.ts | 17 - .../src/pages/password-reset/[token].astro | 67 - .../src/pages/password-reset/index.astro | 65 - .../email-and-password/src/pages/signup.astro | 92 - .../astro/email-and-password/tsconfig.json | 3 - examples/astro/github-oauth/.env.example | 2 - examples/astro/github-oauth/.gitignore | 23 - examples/astro/github-oauth/.prettierignore | 2 - examples/astro/github-oauth/README.md | 27 - examples/astro/github-oauth/astro.config.mjs | 11 - examples/astro/github-oauth/package.json | 24 - .../astro/github-oauth/public/favicon.svg | 9 - examples/astro/github-oauth/schema.sql | 17 - examples/astro/github-oauth/src/app.css | 10 - examples/astro/github-oauth/src/env.d.ts | 15 - examples/astro/github-oauth/src/lib/lucia.ts | 32 - examples/astro/github-oauth/src/middleware.ts | 8 - .../astro/github-oauth/src/pages/index.astro | 24 - .../src/pages/login/github/callback.ts | 53 - .../src/pages/login/github/index.ts | 18 - .../github-oauth/src/pages/login/index.astro | 20 - .../astro/github-oauth/src/pages/logout.ts | 17 - examples/astro/github-oauth/tsconfig.json | 3 - .../astro/username-and-password/.gitignore | 23 - .../username-and-password/.prettierignore | 2 - .../astro/username-and-password/README.md | 18 - .../username-and-password/astro.config.mjs | 11 - .../astro/username-and-password/package.json | 23 - .../username-and-password/public/favicon.svg | 9 - .../astro/username-and-password/schema.sql | 17 - .../astro/username-and-password/src/app.css | 10 - .../astro/username-and-password/src/env.d.ts | 15 - .../username-and-password/src/lib/lucia.ts | 27 - .../username-and-password/src/middleware.ts | 8 - .../src/pages/index.astro | 24 - .../src/pages/login.astro | 87 - .../username-and-password/src/pages/logout.ts | 17 - .../src/pages/signup.astro | 86 - .../astro/username-and-password/tsconfig.json | 3 - examples/electron/github-oauth/README.md | 43 - .../electron/github-oauth/app/.eslintrc.json | 16 - examples/electron/github-oauth/app/.gitignore | 92 - .../electron/github-oauth/app/forge.config.ts | 54 - examples/electron/github-oauth/app/index.html | 21 - .../electron/github-oauth/app/package.json | 41 - .../electron/github-oauth/app/src/index.css | 7 - .../electron/github-oauth/app/src/main.ts | 116 - .../electron/github-oauth/app/src/preload.ts | 58 - .../electron/github-oauth/app/src/types.d.ts | 5 - .../electron/github-oauth/app/tsconfig.json | 16 - .../github-oauth/app/vite.main.config.ts | 10 - .../github-oauth/app/vite.preload.config.ts | 4 - .../github-oauth/app/vite.renderer.config.ts | 4 - .../electron/github-oauth/server/.env.example | 2 - .../electron/github-oauth/server/.gitignore | 2 - .../electron/github-oauth/server/package.json | 18 - .../electron/github-oauth/server/src/app.d.ts | 8 - .../electron/github-oauth/server/src/auth.ts | 37 - .../electron/github-oauth/server/src/index.ts | 74 - .../github-oauth/server/src/schema.sql | 17 - examples/expo/github-oauth/README.md | 46 - examples/expo/github-oauth/app/.gitignore | 35 - examples/expo/github-oauth/app/App.tsx | 92 - examples/expo/github-oauth/app/app.json | 28 - .../github-oauth/app/assets/adaptive-icon.png | Bin 17547 -> 0 bytes .../expo/github-oauth/app/assets/favicon.png | Bin 1466 -> 0 bytes .../expo/github-oauth/app/assets/icon.png | Bin 22380 -> 0 bytes .../expo/github-oauth/app/assets/splash.png | Bin 47346 -> 0 bytes .../expo/github-oauth/app/babel.config.js | 6 - examples/expo/github-oauth/app/package.json | 27 - examples/expo/github-oauth/app/tsconfig.json | 6 - .../expo/github-oauth/server/.env.example | 2 - examples/expo/github-oauth/server/.gitignore | 2 - .../expo/github-oauth/server/package.json | 18 - .../expo/github-oauth/server/src/app.d.ts | 8 - examples/expo/github-oauth/server/src/auth.ts | 37 - .../expo/github-oauth/server/src/index.ts | 75 - .../expo/github-oauth/server/src/schema.sql | 17 - .../express/email-and-password/.gitignore | 3 - examples/express/email-and-password/README.md | 27 - .../express/email-and-password/package.json | 28 - .../express/email-and-password/schema.sql | 28 - .../express/email-and-password/src/app.d.ts | 9 - examples/express/email-and-password/src/db.ts | 49 - .../express/email-and-password/src/email.ts | 16 - .../express/email-and-password/src/index.ts | 25 - .../express/email-and-password/src/lucia.ts | 24 - .../src/routes/email-verification.html | 29 - .../src/routes/email-verification.ts | 87 - .../email-and-password/src/routes/index.html | 27 - .../email-and-password/src/routes/index.ts | 40 - .../email-and-password/src/routes/login.html | 33 - .../email-and-password/src/routes/login.ts | 108 - .../email-and-password/src/routes/logout.ts | 19 - .../src/routes/password-reset/index.html | 30 - .../src/routes/password-reset/index.ts | 88 - .../src/routes/password-reset/token.html | 28 - .../src/routes/password-reset/token.ts | 81 - .../email-and-password/src/routes/signup.html | 32 - .../email-and-password/src/routes/signup.ts | 113 - .../express/email-and-password/src/token.ts | 112 - .../express/email-and-password/tsconfig.json | 11 - examples/express/github-oauth/.env.example | 2 - examples/express/github-oauth/.gitignore | 4 - examples/express/github-oauth/README.md | 35 - examples/express/github-oauth/package.json | 29 - examples/express/github-oauth/schema.sql | 17 - examples/express/github-oauth/src/app.d.ts | 8 - examples/express/github-oauth/src/index.ts | 13 - examples/express/github-oauth/src/lucia.ts | 36 - .../github-oauth/src/routes/index.html | 27 - .../express/github-oauth/src/routes/index.ts | 38 - .../github-oauth/src/routes/login/github.ts | 74 - .../github-oauth/src/routes/login/index.html | 24 - .../github-oauth/src/routes/login/index.ts | 34 - .../express/github-oauth/src/routes/logout.ts | 18 - examples/express/github-oauth/tsconfig.json | 11 - .../express/username-and-password/.gitignore | 3 - .../express/username-and-password/README.md | 26 - .../username-and-password/package.json | 27 - .../express/username-and-password/schema.sql | 17 - .../username-and-password/src/app.d.ts | 8 - .../username-and-password/src/index.ts | 16 - .../username-and-password/src/lucia.ts | 27 - .../src/routes/index.html | 27 - .../username-and-password/src/routes/index.ts | 39 - .../src/routes/login.html | 32 - .../username-and-password/src/routes/login.ts | 108 - .../src/routes/logout.ts | 19 - .../src/routes/signup.html | 32 - .../src/routes/signup.ts | 109 - .../username-and-password/tsconfig.json | 11 - examples/nextjs-app/apple-oauth/.env.example | 5 - .../nextjs-app/apple-oauth/.eslintrc.json | 3 - examples/nextjs-app/apple-oauth/.gitignore | 39 - .../nextjs-app/apple-oauth/.prettierignore | 1 - examples/nextjs-app/apple-oauth/README.md | 51 - examples/nextjs-app/apple-oauth/app.d.ts | 8 - .../nextjs-app/apple-oauth/app/favicon.ico | Bin 25931 -> 0 bytes .../nextjs-app/apple-oauth/app/globals.css | 10 - .../nextjs-app/apple-oauth/app/layout.tsx | 17 - .../app/login/apple/callback/route.ts | 71 - .../apple-oauth/app/login/apple/route.ts | 34 - .../nextjs-app/apple-oauth/app/login/page.tsx | 17 - .../apple-oauth/app/logout/route.ts | 31 - examples/nextjs-app/apple-oauth/app/page.tsx | 25 - examples/nextjs-app/apple-oauth/auth/lucia.ts | 52 - examples/nextjs-app/apple-oauth/cert/.gitkeep | 0 .../apple-oauth/components/form.tsx | 47 - .../nextjs-app/apple-oauth/next.config.js | 4 - examples/nextjs-app/apple-oauth/package.json | 30 - .../nextjs-app/apple-oauth/public/next.svg | 1 - .../nextjs-app/apple-oauth/public/vercel.svg | 1 - examples/nextjs-app/apple-oauth/schema.sql | 17 - examples/nextjs-app/apple-oauth/tsconfig.json | 28 - .../email-and-password/.eslintrc.json | 3 - .../nextjs-app/email-and-password/.gitignore | 37 - .../email-and-password/.prettierignore | 1 - .../nextjs-app/email-and-password/README.md | 27 - .../nextjs-app/email-and-password/app.d.ts | 9 - .../app/api/email-verification/route.ts | 38 - .../email-and-password/app/api/login/route.ts | 80 - .../app/api/logout/route.ts | 25 - .../app/api/password-reset/[token]/route.ts | 66 - .../app/api/password-reset/route.ts | 52 - .../app/api/signup/route.ts | 86 - .../app/email-verification/[token]/route.ts | 41 - .../app/email-verification/page.tsx | 25 - .../email-and-password/app/favicon.ico | Bin 25931 -> 0 bytes .../email-and-password/app/globals.css | 10 - .../email-and-password/app/layout.tsx | 17 - .../email-and-password/app/login/page.tsx | 31 - .../email-and-password/app/page.tsx | 22 - .../app/password-reset/[token]/page.tsx | 29 - .../app/password-reset/page.tsx | 22 - .../email-and-password/app/signup/page.tsx | 30 - .../nextjs-app/email-and-password/auth/db.ts | 49 - .../email-and-password/auth/email.ts | 16 - .../email-and-password/auth/lucia.ts | 34 - .../email-and-password/auth/token.ts | 112 - .../email-and-password/components/form.tsx | 52 - .../email-and-password/next.config.js | 4 - .../email-and-password/package.json | 30 - .../email-and-password/public/next.svg | 1 - .../email-and-password/public/vercel.svg | 1 - .../nextjs-app/email-and-password/schema.sql | 28 - .../email-and-password/tsconfig.json | 28 - examples/nextjs-app/github-oauth/.env.example | 2 - .../nextjs-app/github-oauth/.eslintrc.json | 3 - examples/nextjs-app/github-oauth/.gitignore | 38 - .../nextjs-app/github-oauth/.prettierignore | 1 - examples/nextjs-app/github-oauth/README.md | 35 - examples/nextjs-app/github-oauth/app.d.ts | 8 - .../nextjs-app/github-oauth/app/favicon.ico | Bin 25931 -> 0 bytes .../nextjs-app/github-oauth/app/globals.css | 10 - .../nextjs-app/github-oauth/app/layout.tsx | 17 - .../app/login/github/callback/route.ts | 70 - .../github-oauth/app/login/github/route.ts | 31 - .../github-oauth/app/login/page.tsx | 15 - .../github-oauth/app/logout/route.ts | 25 - examples/nextjs-app/github-oauth/app/page.tsx | 21 - .../nextjs-app/github-oauth/auth/lucia.ts | 44 - .../github-oauth/components/form.tsx | 49 - .../nextjs-app/github-oauth/next.config.js | 4 - examples/nextjs-app/github-oauth/package.json | 30 - .../nextjs-app/github-oauth/public/next.svg | 1 - .../nextjs-app/github-oauth/public/vercel.svg | 1 - examples/nextjs-app/github-oauth/schema.sql | 17 - .../nextjs-app/github-oauth/tsconfig.json | 28 - .../username-and-password/.eslintrc.json | 3 - .../username-and-password/.gitignore | 37 - .../username-and-password/.prettierignore | 1 - .../username-and-password/README.md | 26 - .../nextjs-app/username-and-password/app.d.ts | 8 - .../app/api/login/route.ts | 83 - .../app/api/logout/route.ts | 25 - .../app/api/signup/route.ts | 85 - .../username-and-password/app/favicon.ico | Bin 25931 -> 0 bytes .../username-and-password/app/globals.css | 10 - .../username-and-password/app/layout.tsx | 17 - .../username-and-password/app/login/page.tsx | 27 - .../username-and-password/app/page.tsx | 21 - .../username-and-password/app/signup/page.tsx | 27 - .../username-and-password/auth/lucia.ts | 38 - .../username-and-password/components/form.tsx | 49 - .../username-and-password/next.config.js | 4 - .../username-and-password/package.json | 29 - .../username-and-password/public/next.svg | 1 - .../username-and-password/public/vercel.svg | 1 - .../username-and-password/schema.sql | 17 - .../username-and-password/tsconfig.json | 28 - .../email-and-password/.eslintrc.json | 3 - .../email-and-password/.gitignore | 37 - .../email-and-password/.prettierignore | 1 - .../nextjs-pages/email-and-password/README.md | 27 - .../nextjs-pages/email-and-password/app.d.ts | 9 - .../email-and-password/auth/db.ts | 49 - .../email-and-password/auth/email.ts | 16 - .../email-and-password/auth/lucia.ts | 24 - .../email-and-password/auth/token.ts | 112 - .../email-and-password/next.config.js | 6 - .../email-and-password/package-lock.json | 3523 ----------------- .../email-and-password/package.json | 30 - .../email-and-password/pages/_app.tsx | 16 - .../pages/api/email-verification/[token].ts | 33 - .../pages/api/email-verification/index.ts | 32 - .../email-and-password/pages/api/login.ts | 59 - .../email-and-password/pages/api/logout.ts | 20 - .../pages/api/password-reset/[token].ts | 50 - .../pages/api/password-reset/index.ts | 41 - .../email-and-password/pages/api/signup.ts | 67 - .../pages/email-verification.tsx | 68 - .../email-and-password/pages/index.tsx | 75 - .../email-and-password/pages/login.tsx | 88 - .../pages/password-reset/[token].tsx | 79 - .../pages/password-reset/index.tsx | 50 - .../email-and-password/pages/signup.tsx | 86 - .../email-and-password/public/favicon.ico | Bin 25931 -> 0 bytes .../email-and-password/schema.sql | 28 - .../email-and-password/styles/globals.css | 10 - .../email-and-password/tsconfig.json | 23 - .../nextjs-pages/github-oauth/.env.example | 2 - .../nextjs-pages/github-oauth/.eslintrc.json | 3 - examples/nextjs-pages/github-oauth/.gitignore | 38 - .../nextjs-pages/github-oauth/.prettierignore | 1 - examples/nextjs-pages/github-oauth/README.md | 35 - examples/nextjs-pages/github-oauth/app.d.ts | 8 - .../nextjs-pages/github-oauth/auth/lucia.ts | 33 - .../nextjs-pages/github-oauth/next.config.js | 6 - .../github-oauth/package-lock.json | 3523 ----------------- .../nextjs-pages/github-oauth/package.json | 30 - .../nextjs-pages/github-oauth/pages/_app.tsx | 16 - .../pages/api/login/github/callback.ts | 58 - .../pages/api/login/github/index.ts | 27 - .../github-oauth/pages/api/logout.ts | 20 - .../nextjs-pages/github-oauth/pages/index.tsx | 67 - .../nextjs-pages/github-oauth/pages/login.tsx | 32 - .../github-oauth/public/favicon.ico | Bin 25931 -> 0 bytes examples/nextjs-pages/github-oauth/schema.sql | 17 - .../github-oauth/styles/globals.css | 10 - .../nextjs-pages/github-oauth/tsconfig.json | 23 - .../username-and-password/.eslintrc.json | 3 - .../username-and-password/.gitignore | 37 - .../username-and-password/.prettierignore | 1 - .../username-and-password/README.md | 26 - .../username-and-password/app.d.ts | 8 - .../username-and-password/auth/lucia.ts | 27 - .../username-and-password/next.config.js | 6 - .../username-and-password/package-lock.json | 3523 ----------------- .../username-and-password/package.json | 29 - .../username-and-password/pages/_app.tsx | 16 - .../username-and-password/pages/api/login.ts | 63 - .../username-and-password/pages/api/logout.ts | 20 - .../username-and-password/pages/api/signup.ts | 66 - .../username-and-password/pages/index.tsx | 67 - .../username-and-password/pages/login.tsx | 79 - .../username-and-password/pages/signup.tsx | 78 - .../username-and-password/public/favicon.ico | Bin 25931 -> 0 bytes .../username-and-password/schema.sql | 17 - .../username-and-password/styles/globals.css | 10 - .../username-and-password/tsconfig.json | 23 - examples/nuxt/email-and-password/.gitignore | 25 - examples/nuxt/email-and-password/.npmrc | 1 - .../nuxt/email-and-password/.prettierignore | 1 - examples/nuxt/email-and-password/README.md | 35 - examples/nuxt/email-and-password/app.vue | 18 - .../email-and-password/composables/auth.ts | 19 - .../middleware/auth.global.ts | 6 - .../middleware/protected.ts | 4 - .../nuxt/email-and-password/nuxt.config.ts | 12 - examples/nuxt/email-and-password/package.json | 23 - .../pages/email-verification.vue | 37 - .../nuxt/email-and-password/pages/index.vue | 29 - .../nuxt/email-and-password/pages/login.vue | 50 - .../pages/password-reset/[token].vue | 40 - .../pages/password-reset/index.vue | 44 - .../nuxt/email-and-password/pages/signup.vue | 49 - .../email-and-password/public/favicon.ico | Bin 4286 -> 0 bytes examples/nuxt/email-and-password/schema.sql | 28 - .../api/email-verification/[token].get.ts | 25 - .../api/email-verification/index.post.ts | 26 - .../server/api/login.post.ts | 54 - .../server/api/logout.post.ts | 16 - .../server/api/password-reset/[token].post.ts | 38 - .../server/api/password-reset/index.post.ts | 28 - .../server/api/signup.post.ts | 59 - .../email-and-password/server/api/user.get.ts | 7 - .../nuxt/email-and-password/server/app.d.ts | 9 - .../email-and-password/server/tsconfig.json | 6 - .../email-and-password/server/utils/db.ts | 49 - .../email-and-password/server/utils/email.ts | 16 - .../email-and-password/server/utils/lucia.ts | 24 - .../email-and-password/server/utils/token.ts | 112 - .../nuxt/email-and-password/tsconfig.json | 4 - examples/nuxt/github-oauth/.env.example | 2 - examples/nuxt/github-oauth/.gitignore | 25 - examples/nuxt/github-oauth/.npmrc | 1 - examples/nuxt/github-oauth/.prettierignore | 1 - examples/nuxt/github-oauth/README.md | 43 - examples/nuxt/github-oauth/app.vue | 18 - .../nuxt/github-oauth/composables/auth.ts | 19 - .../github-oauth/middleware/auth.global.ts | 6 - .../nuxt/github-oauth/middleware/protected.ts | 4 - examples/nuxt/github-oauth/nuxt.config.ts | 16 - examples/nuxt/github-oauth/package.json | 23 - examples/nuxt/github-oauth/pages/index.vue | 25 - examples/nuxt/github-oauth/pages/login.vue | 11 - examples/nuxt/github-oauth/public/favicon.ico | Bin 4286 -> 0 bytes examples/nuxt/github-oauth/schema.sql | 17 - .../server/api/login/github/callback.get.ts | 61 - .../server/api/login/github/index.get.ts | 15 - .../github-oauth/server/api/logout.post.ts | 16 - .../nuxt/github-oauth/server/api/user.get.ts | 7 - examples/nuxt/github-oauth/server/app.d.ts | 8 - .../nuxt/github-oauth/server/tsconfig.json | 6 - .../nuxt/github-oauth/server/utils/lucia.ts | 35 - examples/nuxt/github-oauth/tsconfig.json | 4 - .../nuxt/username-and-password/.gitignore | 25 - examples/nuxt/username-and-password/.npmrc | 1 - .../username-and-password/.prettierignore | 1 - examples/nuxt/username-and-password/README.md | 34 - examples/nuxt/username-and-password/app.vue | 18 - .../username-and-password/composables/auth.ts | 19 - .../middleware/auth.global.ts | 6 - .../middleware/protected.ts | 4 - .../nuxt/username-and-password/nuxt.config.ts | 12 - .../nuxt/username-and-password/package.json | 22 - .../username-and-password/pages/index.vue | 25 - .../username-and-password/pages/login.vue | 44 - .../username-and-password/pages/signup.vue | 44 - .../username-and-password/public/favicon.ico | Bin 4286 -> 0 bytes .../nuxt/username-and-password/schema.sql | 17 - .../server/api/login.post.ts | 58 - .../server/api/logout.post.ts | 16 - .../server/api/signup.post.ts | 60 - .../server/api/user.get.ts | 7 - .../username-and-password/server/app.d.ts | 8 - .../server/tsconfig.json | 6 - .../server/utils/lucia.ts | 27 - .../nuxt/username-and-password/tsconfig.json | 4 - .../login-throttling-device-cookie/README.md | 10 - .../package.json | 14 - .../src/index.html | 24 - .../src/index.ts | 110 - examples/other/login-throttling/README.md | 10 - examples/other/login-throttling/package.json | 13 - .../other/login-throttling/src/index.html | 20 - examples/other/login-throttling/src/index.ts | 53 - examples/solidstart/github-oauth/.env.example | 2 - examples/solidstart/github-oauth/.gitignore | 30 - examples/solidstart/github-oauth/README.md | 26 - examples/solidstart/github-oauth/package.json | 29 - .../github-oauth/public/favicon.ico | Bin 664 -> 0 bytes examples/solidstart/github-oauth/schema.sql | 17 - examples/solidstart/github-oauth/src/app.d.ts | 8 - .../solidstart/github-oauth/src/auth/lucia.ts | 36 - .../github-oauth/src/entry-client.tsx | 3 - .../github-oauth/src/entry-server.tsx | 9 - examples/solidstart/github-oauth/src/root.css | 10 - examples/solidstart/github-oauth/src/root.tsx | 36 - .../github-oauth/src/routes/[...404].tsx | 12 - .../github-oauth/src/routes/index.tsx | 53 - .../src/routes/login/github/callback.ts | 63 - .../src/routes/login/github/index.ts | 26 - .../github-oauth/src/routes/login/index.tsx | 23 - .../solidstart/github-oauth/tsconfig.json | 17 - .../solidstart/github-oauth/vite.config.ts | 6 - .../username-and-password/.gitignore | 30 - .../username-and-password/README.md | 26 - .../username-and-password/package.json | 28 - .../username-and-password/public/favicon.ico | Bin 664 -> 0 bytes .../username-and-password/schema.sql | 17 - .../username-and-password/src/app.d.ts | 8 - .../username-and-password/src/auth/lucia.ts | 30 - .../src/entry-client.tsx | 3 - .../src/entry-server.tsx | 9 - .../username-and-password/src/root.css | 10 - .../username-and-password/src/root.tsx | 36 - .../src/routes/[...404].tsx | 12 - .../src/routes/index.tsx | 53 - .../src/routes/login.tsx | 97 - .../src/routes/signup.tsx | 97 - .../username-and-password/tsconfig.json | 17 - .../username-and-password/vite.config.ts | 6 - .../email-and-password/.eslintignore | 13 - .../email-and-password/.eslintrc.cjs | 30 - .../sveltekit/email-and-password/.gitignore | 12 - examples/sveltekit/email-and-password/.npmrc | 2 - .../email-and-password/.prettierignore | 13 - .../sveltekit/email-and-password/.prettierrc | 9 - .../sveltekit/email-and-password/README.md | 19 - .../sveltekit/email-and-password/package.json | 39 - .../sveltekit/email-and-password/schema.sql | 28 - .../sveltekit/email-and-password/src/app.css | 10 - .../sveltekit/email-and-password/src/app.d.ts | 23 - .../sveltekit/email-and-password/src/app.html | 12 - .../email-and-password/src/hooks.server.ts | 8 - .../email-and-password/src/lib/server/db.ts | 49 - .../src/lib/server/email.ts | 16 - .../src/lib/server/lucia.ts | 24 - .../src/lib/server/token.ts | 109 - .../src/routes/+layout.svelte | 8 - .../src/routes/+page.server.ts | 26 - .../src/routes/+page.svelte | 14 - .../routes/email-verification/+page.server.ts | 35 - .../routes/email-verification/+page.svelte | 17 - .../email-verification/[token]/+server.ts | 31 - .../src/routes/login/+page.server.ts | 60 - .../src/routes/login/+page.svelte | 21 - .../src/routes/password-reset/+page.server.ts | 42 - .../src/routes/password-reset/+page.svelte | 21 - .../password-reset/[token]/+page.server.ts | 49 - .../password-reset/[token]/+page.svelte | 17 - .../src/routes/signup/+page.server.ts | 68 - .../src/routes/signup/+page.svelte | 20 - .../email-and-password/static/favicon.png | Bin 1571 -> 0 bytes .../email-and-password/svelte.config.js | 18 - .../email-and-password/tsconfig.json | 17 - .../email-and-password/vite.config.ts | 6 - examples/sveltekit/github-oauth/.env.example | 2 - examples/sveltekit/github-oauth/.eslintignore | 13 - examples/sveltekit/github-oauth/.eslintrc.cjs | 30 - examples/sveltekit/github-oauth/.gitignore | 12 - examples/sveltekit/github-oauth/.npmrc | 2 - .../sveltekit/github-oauth/.prettierignore | 13 - examples/sveltekit/github-oauth/.prettierrc | 9 - examples/sveltekit/github-oauth/README.md | 27 - examples/sveltekit/github-oauth/package.json | 39 - examples/sveltekit/github-oauth/schema.sql | 17 - examples/sveltekit/github-oauth/src/app.css | 10 - examples/sveltekit/github-oauth/src/app.d.ts | 22 - examples/sveltekit/github-oauth/src/app.html | 12 - .../github-oauth/src/hooks.server.ts | 8 - .../github-oauth/src/lib/server/lucia.ts | 34 - .../github-oauth/src/routes/+layout.svelte | 8 - .../github-oauth/src/routes/+page.server.ts | 23 - .../github-oauth/src/routes/+page.svelte | 14 - .../src/routes/login/+page.server.ts | 7 - .../src/routes/login/+page.svelte | 2 - .../src/routes/login/github/+server.ts | 27 - .../routes/login/github/callback/+server.ts | 60 - .../sveltekit/github-oauth/static/favicon.png | Bin 1571 -> 0 bytes .../sveltekit/github-oauth/svelte.config.js | 18 - examples/sveltekit/github-oauth/tsconfig.json | 17 - .../sveltekit/github-oauth/vite.config.ts | 6 - .../username-and-password/.eslintignore | 13 - .../username-and-password/.eslintrc.cjs | 30 - .../username-and-password/.gitignore | 12 - .../sveltekit/username-and-password/.npmrc | 2 - .../username-and-password/.prettierignore | 13 - .../username-and-password/.prettierrc | 9 - .../sveltekit/username-and-password/README.md | 18 - .../username-and-password/package.json | 38 - .../username-and-password/schema.sql | 17 - .../username-and-password/src/app.css | 10 - .../username-and-password/src/app.d.ts | 22 - .../username-and-password/src/app.html | 12 - .../username-and-password/src/hooks.server.ts | 8 - .../src/lib/server/lucia.ts | 27 - .../src/routes/+layout.svelte | 8 - .../src/routes/+page.server.ts | 23 - .../src/routes/+page.svelte | 14 - .../src/routes/login/+page.server.ts | 57 - .../src/routes/login/+page.svelte | 20 - .../src/routes/signup/+page.server.ts | 60 - .../src/routes/signup/+page.svelte | 20 - .../username-and-password/static/favicon.png | Bin 1571 -> 0 bytes .../username-and-password/svelte.config.js | 18 - .../username-and-password/tsconfig.json | 17 - .../username-and-password/vite.config.ts | 6 - examples/tauri/github-oauth/README.md | 43 - examples/tauri/github-oauth/app/.gitignore | 24 - examples/tauri/github-oauth/app/index.html | 24 - examples/tauri/github-oauth/app/package.json | 20 - .../github-oauth/app/src-tauri/.gitignore | 5 - .../github-oauth/app/src-tauri/Cargo.toml | 24 - .../tauri/github-oauth/app/src-tauri/build.rs | 3 - .../app/src-tauri/icons/128x128.png | Bin 3512 -> 0 bytes .../app/src-tauri/icons/128x128@2x.png | Bin 7012 -> 0 bytes .../app/src-tauri/icons/32x32.png | Bin 974 -> 0 bytes .../app/src-tauri/icons/Square107x107Logo.png | Bin 2863 -> 0 bytes .../app/src-tauri/icons/Square142x142Logo.png | Bin 3858 -> 0 bytes .../app/src-tauri/icons/Square150x150Logo.png | Bin 3966 -> 0 bytes .../app/src-tauri/icons/Square284x284Logo.png | Bin 7737 -> 0 bytes .../app/src-tauri/icons/Square30x30Logo.png | Bin 903 -> 0 bytes .../app/src-tauri/icons/Square310x310Logo.png | Bin 8591 -> 0 bytes .../app/src-tauri/icons/Square44x44Logo.png | Bin 1299 -> 0 bytes .../app/src-tauri/icons/Square71x71Logo.png | Bin 2011 -> 0 bytes .../app/src-tauri/icons/Square89x89Logo.png | Bin 2468 -> 0 bytes .../app/src-tauri/icons/StoreLogo.png | Bin 1523 -> 0 bytes .../app/src-tauri/icons/icon.icns | Bin 98451 -> 0 bytes .../github-oauth/app/src-tauri/icons/icon.ico | Bin 86642 -> 0 bytes .../github-oauth/app/src-tauri/icons/icon.png | Bin 14183 -> 0 bytes .../github-oauth/app/src-tauri/src/main.rs | 45 - .../app/src-tauri/tauri.conf.json | 48 - examples/tauri/github-oauth/app/src/main.ts | 67 - .../tauri/github-oauth/app/src/styles.css | 7 - examples/tauri/github-oauth/app/tsconfig.json | 23 - .../tauri/github-oauth/app/vite.config.ts | 17 - .../tauri/github-oauth/server/.env.example | 2 - examples/tauri/github-oauth/server/.gitignore | 2 - .../tauri/github-oauth/server/package.json | 18 - .../tauri/github-oauth/server/src/app.d.ts | 8 - .../tauri/github-oauth/server/src/auth.ts | 37 - .../tauri/github-oauth/server/src/index.ts | 85 - .../tauri/github-oauth/server/src/schema.sql | 17 - package.json | 1 - pnpm-workspace.yaml | 1 - 597 files changed, 96 insertions(+), 24897 deletions(-) delete mode 100644 examples/astro/email-and-password/.gitignore delete mode 100644 examples/astro/email-and-password/.prettierignore delete mode 100644 examples/astro/email-and-password/README.md delete mode 100644 examples/astro/email-and-password/astro.config.mjs delete mode 100644 examples/astro/email-and-password/package.json delete mode 100644 examples/astro/email-and-password/public/favicon.svg delete mode 100644 examples/astro/email-and-password/schema.sql delete mode 100644 examples/astro/email-and-password/src/app.css delete mode 100644 examples/astro/email-and-password/src/env.d.ts delete mode 100644 examples/astro/email-and-password/src/lib/db.ts delete mode 100644 examples/astro/email-and-password/src/lib/email.ts delete mode 100644 examples/astro/email-and-password/src/lib/lucia.ts delete mode 100644 examples/astro/email-and-password/src/lib/token.ts delete mode 100644 examples/astro/email-and-password/src/middleware.ts delete mode 100644 examples/astro/email-and-password/src/pages/email-verification/[token].ts delete mode 100644 examples/astro/email-and-password/src/pages/email-verification/index.astro delete mode 100644 examples/astro/email-and-password/src/pages/index.astro delete mode 100644 examples/astro/email-and-password/src/pages/login.astro delete mode 100644 examples/astro/email-and-password/src/pages/logout.ts delete mode 100644 examples/astro/email-and-password/src/pages/password-reset/[token].astro delete mode 100644 examples/astro/email-and-password/src/pages/password-reset/index.astro delete mode 100644 examples/astro/email-and-password/src/pages/signup.astro delete mode 100644 examples/astro/email-and-password/tsconfig.json delete mode 100644 examples/astro/github-oauth/.env.example delete mode 100644 examples/astro/github-oauth/.gitignore delete mode 100644 examples/astro/github-oauth/.prettierignore delete mode 100644 examples/astro/github-oauth/README.md delete mode 100644 examples/astro/github-oauth/astro.config.mjs delete mode 100644 examples/astro/github-oauth/package.json delete mode 100644 examples/astro/github-oauth/public/favicon.svg delete mode 100644 examples/astro/github-oauth/schema.sql delete mode 100644 examples/astro/github-oauth/src/app.css delete mode 100644 examples/astro/github-oauth/src/env.d.ts delete mode 100644 examples/astro/github-oauth/src/lib/lucia.ts delete mode 100644 examples/astro/github-oauth/src/middleware.ts delete mode 100644 examples/astro/github-oauth/src/pages/index.astro delete mode 100644 examples/astro/github-oauth/src/pages/login/github/callback.ts delete mode 100644 examples/astro/github-oauth/src/pages/login/github/index.ts delete mode 100644 examples/astro/github-oauth/src/pages/login/index.astro delete mode 100644 examples/astro/github-oauth/src/pages/logout.ts delete mode 100644 examples/astro/github-oauth/tsconfig.json delete mode 100644 examples/astro/username-and-password/.gitignore delete mode 100644 examples/astro/username-and-password/.prettierignore delete mode 100644 examples/astro/username-and-password/README.md delete mode 100644 examples/astro/username-and-password/astro.config.mjs delete mode 100644 examples/astro/username-and-password/package.json delete mode 100644 examples/astro/username-and-password/public/favicon.svg delete mode 100644 examples/astro/username-and-password/schema.sql delete mode 100644 examples/astro/username-and-password/src/app.css delete mode 100644 examples/astro/username-and-password/src/env.d.ts delete mode 100644 examples/astro/username-and-password/src/lib/lucia.ts delete mode 100644 examples/astro/username-and-password/src/middleware.ts delete mode 100644 examples/astro/username-and-password/src/pages/index.astro delete mode 100644 examples/astro/username-and-password/src/pages/login.astro delete mode 100644 examples/astro/username-and-password/src/pages/logout.ts delete mode 100644 examples/astro/username-and-password/src/pages/signup.astro delete mode 100644 examples/astro/username-and-password/tsconfig.json delete mode 100644 examples/electron/github-oauth/README.md delete mode 100644 examples/electron/github-oauth/app/.eslintrc.json delete mode 100644 examples/electron/github-oauth/app/.gitignore delete mode 100644 examples/electron/github-oauth/app/forge.config.ts delete mode 100644 examples/electron/github-oauth/app/index.html delete mode 100644 examples/electron/github-oauth/app/package.json delete mode 100644 examples/electron/github-oauth/app/src/index.css delete mode 100644 examples/electron/github-oauth/app/src/main.ts delete mode 100644 examples/electron/github-oauth/app/src/preload.ts delete mode 100644 examples/electron/github-oauth/app/src/types.d.ts delete mode 100644 examples/electron/github-oauth/app/tsconfig.json delete mode 100644 examples/electron/github-oauth/app/vite.main.config.ts delete mode 100644 examples/electron/github-oauth/app/vite.preload.config.ts delete mode 100644 examples/electron/github-oauth/app/vite.renderer.config.ts delete mode 100644 examples/electron/github-oauth/server/.env.example delete mode 100644 examples/electron/github-oauth/server/.gitignore delete mode 100644 examples/electron/github-oauth/server/package.json delete mode 100644 examples/electron/github-oauth/server/src/app.d.ts delete mode 100644 examples/electron/github-oauth/server/src/auth.ts delete mode 100644 examples/electron/github-oauth/server/src/index.ts delete mode 100644 examples/electron/github-oauth/server/src/schema.sql delete mode 100644 examples/expo/github-oauth/README.md delete mode 100644 examples/expo/github-oauth/app/.gitignore delete mode 100644 examples/expo/github-oauth/app/App.tsx delete mode 100644 examples/expo/github-oauth/app/app.json delete mode 100644 examples/expo/github-oauth/app/assets/adaptive-icon.png delete mode 100644 examples/expo/github-oauth/app/assets/favicon.png delete mode 100644 examples/expo/github-oauth/app/assets/icon.png delete mode 100644 examples/expo/github-oauth/app/assets/splash.png delete mode 100644 examples/expo/github-oauth/app/babel.config.js delete mode 100644 examples/expo/github-oauth/app/package.json delete mode 100644 examples/expo/github-oauth/app/tsconfig.json delete mode 100644 examples/expo/github-oauth/server/.env.example delete mode 100644 examples/expo/github-oauth/server/.gitignore delete mode 100644 examples/expo/github-oauth/server/package.json delete mode 100644 examples/expo/github-oauth/server/src/app.d.ts delete mode 100644 examples/expo/github-oauth/server/src/auth.ts delete mode 100644 examples/expo/github-oauth/server/src/index.ts delete mode 100644 examples/expo/github-oauth/server/src/schema.sql delete mode 100644 examples/express/email-and-password/.gitignore delete mode 100644 examples/express/email-and-password/README.md delete mode 100644 examples/express/email-and-password/package.json delete mode 100644 examples/express/email-and-password/schema.sql delete mode 100644 examples/express/email-and-password/src/app.d.ts delete mode 100644 examples/express/email-and-password/src/db.ts delete mode 100644 examples/express/email-and-password/src/email.ts delete mode 100644 examples/express/email-and-password/src/index.ts delete mode 100644 examples/express/email-and-password/src/lucia.ts delete mode 100644 examples/express/email-and-password/src/routes/email-verification.html delete mode 100644 examples/express/email-and-password/src/routes/email-verification.ts delete mode 100644 examples/express/email-and-password/src/routes/index.html delete mode 100644 examples/express/email-and-password/src/routes/index.ts delete mode 100644 examples/express/email-and-password/src/routes/login.html delete mode 100644 examples/express/email-and-password/src/routes/login.ts delete mode 100644 examples/express/email-and-password/src/routes/logout.ts delete mode 100644 examples/express/email-and-password/src/routes/password-reset/index.html delete mode 100644 examples/express/email-and-password/src/routes/password-reset/index.ts delete mode 100644 examples/express/email-and-password/src/routes/password-reset/token.html delete mode 100644 examples/express/email-and-password/src/routes/password-reset/token.ts delete mode 100644 examples/express/email-and-password/src/routes/signup.html delete mode 100644 examples/express/email-and-password/src/routes/signup.ts delete mode 100644 examples/express/email-and-password/src/token.ts delete mode 100644 examples/express/email-and-password/tsconfig.json delete mode 100644 examples/express/github-oauth/.env.example delete mode 100644 examples/express/github-oauth/.gitignore delete mode 100644 examples/express/github-oauth/README.md delete mode 100644 examples/express/github-oauth/package.json delete mode 100644 examples/express/github-oauth/schema.sql delete mode 100644 examples/express/github-oauth/src/app.d.ts delete mode 100644 examples/express/github-oauth/src/index.ts delete mode 100644 examples/express/github-oauth/src/lucia.ts delete mode 100644 examples/express/github-oauth/src/routes/index.html delete mode 100644 examples/express/github-oauth/src/routes/index.ts delete mode 100644 examples/express/github-oauth/src/routes/login/github.ts delete mode 100644 examples/express/github-oauth/src/routes/login/index.html delete mode 100644 examples/express/github-oauth/src/routes/login/index.ts delete mode 100644 examples/express/github-oauth/src/routes/logout.ts delete mode 100644 examples/express/github-oauth/tsconfig.json delete mode 100644 examples/express/username-and-password/.gitignore delete mode 100644 examples/express/username-and-password/README.md delete mode 100644 examples/express/username-and-password/package.json delete mode 100644 examples/express/username-and-password/schema.sql delete mode 100644 examples/express/username-and-password/src/app.d.ts delete mode 100644 examples/express/username-and-password/src/index.ts delete mode 100644 examples/express/username-and-password/src/lucia.ts delete mode 100644 examples/express/username-and-password/src/routes/index.html delete mode 100644 examples/express/username-and-password/src/routes/index.ts delete mode 100644 examples/express/username-and-password/src/routes/login.html delete mode 100644 examples/express/username-and-password/src/routes/login.ts delete mode 100644 examples/express/username-and-password/src/routes/logout.ts delete mode 100644 examples/express/username-and-password/src/routes/signup.html delete mode 100644 examples/express/username-and-password/src/routes/signup.ts delete mode 100644 examples/express/username-and-password/tsconfig.json delete mode 100644 examples/nextjs-app/apple-oauth/.env.example delete mode 100644 examples/nextjs-app/apple-oauth/.eslintrc.json delete mode 100644 examples/nextjs-app/apple-oauth/.gitignore delete mode 100644 examples/nextjs-app/apple-oauth/.prettierignore delete mode 100644 examples/nextjs-app/apple-oauth/README.md delete mode 100644 examples/nextjs-app/apple-oauth/app.d.ts delete mode 100644 examples/nextjs-app/apple-oauth/app/favicon.ico delete mode 100644 examples/nextjs-app/apple-oauth/app/globals.css delete mode 100644 examples/nextjs-app/apple-oauth/app/layout.tsx delete mode 100644 examples/nextjs-app/apple-oauth/app/login/apple/callback/route.ts delete mode 100644 examples/nextjs-app/apple-oauth/app/login/apple/route.ts delete mode 100644 examples/nextjs-app/apple-oauth/app/login/page.tsx delete mode 100644 examples/nextjs-app/apple-oauth/app/logout/route.ts delete mode 100644 examples/nextjs-app/apple-oauth/app/page.tsx delete mode 100644 examples/nextjs-app/apple-oauth/auth/lucia.ts delete mode 100644 examples/nextjs-app/apple-oauth/cert/.gitkeep delete mode 100644 examples/nextjs-app/apple-oauth/components/form.tsx delete mode 100644 examples/nextjs-app/apple-oauth/next.config.js delete mode 100644 examples/nextjs-app/apple-oauth/package.json delete mode 100644 examples/nextjs-app/apple-oauth/public/next.svg delete mode 100644 examples/nextjs-app/apple-oauth/public/vercel.svg delete mode 100644 examples/nextjs-app/apple-oauth/schema.sql delete mode 100644 examples/nextjs-app/apple-oauth/tsconfig.json delete mode 100644 examples/nextjs-app/email-and-password/.eslintrc.json delete mode 100644 examples/nextjs-app/email-and-password/.gitignore delete mode 100644 examples/nextjs-app/email-and-password/.prettierignore delete mode 100644 examples/nextjs-app/email-and-password/README.md delete mode 100644 examples/nextjs-app/email-and-password/app.d.ts delete mode 100644 examples/nextjs-app/email-and-password/app/api/email-verification/route.ts delete mode 100644 examples/nextjs-app/email-and-password/app/api/login/route.ts delete mode 100644 examples/nextjs-app/email-and-password/app/api/logout/route.ts delete mode 100644 examples/nextjs-app/email-and-password/app/api/password-reset/[token]/route.ts delete mode 100644 examples/nextjs-app/email-and-password/app/api/password-reset/route.ts delete mode 100644 examples/nextjs-app/email-and-password/app/api/signup/route.ts delete mode 100644 examples/nextjs-app/email-and-password/app/email-verification/[token]/route.ts delete mode 100644 examples/nextjs-app/email-and-password/app/email-verification/page.tsx delete mode 100644 examples/nextjs-app/email-and-password/app/favicon.ico delete mode 100644 examples/nextjs-app/email-and-password/app/globals.css delete mode 100644 examples/nextjs-app/email-and-password/app/layout.tsx delete mode 100644 examples/nextjs-app/email-and-password/app/login/page.tsx delete mode 100644 examples/nextjs-app/email-and-password/app/page.tsx delete mode 100644 examples/nextjs-app/email-and-password/app/password-reset/[token]/page.tsx delete mode 100644 examples/nextjs-app/email-and-password/app/password-reset/page.tsx delete mode 100644 examples/nextjs-app/email-and-password/app/signup/page.tsx delete mode 100644 examples/nextjs-app/email-and-password/auth/db.ts delete mode 100644 examples/nextjs-app/email-and-password/auth/email.ts delete mode 100644 examples/nextjs-app/email-and-password/auth/lucia.ts delete mode 100644 examples/nextjs-app/email-and-password/auth/token.ts delete mode 100644 examples/nextjs-app/email-and-password/components/form.tsx delete mode 100644 examples/nextjs-app/email-and-password/next.config.js delete mode 100644 examples/nextjs-app/email-and-password/package.json delete mode 100644 examples/nextjs-app/email-and-password/public/next.svg delete mode 100644 examples/nextjs-app/email-and-password/public/vercel.svg delete mode 100644 examples/nextjs-app/email-and-password/schema.sql delete mode 100644 examples/nextjs-app/email-and-password/tsconfig.json delete mode 100644 examples/nextjs-app/github-oauth/.env.example delete mode 100644 examples/nextjs-app/github-oauth/.eslintrc.json delete mode 100644 examples/nextjs-app/github-oauth/.gitignore delete mode 100644 examples/nextjs-app/github-oauth/.prettierignore delete mode 100644 examples/nextjs-app/github-oauth/README.md delete mode 100644 examples/nextjs-app/github-oauth/app.d.ts delete mode 100644 examples/nextjs-app/github-oauth/app/favicon.ico delete mode 100644 examples/nextjs-app/github-oauth/app/globals.css delete mode 100644 examples/nextjs-app/github-oauth/app/layout.tsx delete mode 100644 examples/nextjs-app/github-oauth/app/login/github/callback/route.ts delete mode 100644 examples/nextjs-app/github-oauth/app/login/github/route.ts delete mode 100644 examples/nextjs-app/github-oauth/app/login/page.tsx delete mode 100644 examples/nextjs-app/github-oauth/app/logout/route.ts delete mode 100644 examples/nextjs-app/github-oauth/app/page.tsx delete mode 100644 examples/nextjs-app/github-oauth/auth/lucia.ts delete mode 100644 examples/nextjs-app/github-oauth/components/form.tsx delete mode 100644 examples/nextjs-app/github-oauth/next.config.js delete mode 100644 examples/nextjs-app/github-oauth/package.json delete mode 100644 examples/nextjs-app/github-oauth/public/next.svg delete mode 100644 examples/nextjs-app/github-oauth/public/vercel.svg delete mode 100644 examples/nextjs-app/github-oauth/schema.sql delete mode 100644 examples/nextjs-app/github-oauth/tsconfig.json delete mode 100644 examples/nextjs-app/username-and-password/.eslintrc.json delete mode 100644 examples/nextjs-app/username-and-password/.gitignore delete mode 100644 examples/nextjs-app/username-and-password/.prettierignore delete mode 100644 examples/nextjs-app/username-and-password/README.md delete mode 100644 examples/nextjs-app/username-and-password/app.d.ts delete mode 100644 examples/nextjs-app/username-and-password/app/api/login/route.ts delete mode 100644 examples/nextjs-app/username-and-password/app/api/logout/route.ts delete mode 100644 examples/nextjs-app/username-and-password/app/api/signup/route.ts delete mode 100644 examples/nextjs-app/username-and-password/app/favicon.ico delete mode 100644 examples/nextjs-app/username-and-password/app/globals.css delete mode 100644 examples/nextjs-app/username-and-password/app/layout.tsx delete mode 100644 examples/nextjs-app/username-and-password/app/login/page.tsx delete mode 100644 examples/nextjs-app/username-and-password/app/page.tsx delete mode 100644 examples/nextjs-app/username-and-password/app/signup/page.tsx delete mode 100644 examples/nextjs-app/username-and-password/auth/lucia.ts delete mode 100644 examples/nextjs-app/username-and-password/components/form.tsx delete mode 100644 examples/nextjs-app/username-and-password/next.config.js delete mode 100644 examples/nextjs-app/username-and-password/package.json delete mode 100644 examples/nextjs-app/username-and-password/public/next.svg delete mode 100644 examples/nextjs-app/username-and-password/public/vercel.svg delete mode 100644 examples/nextjs-app/username-and-password/schema.sql delete mode 100644 examples/nextjs-app/username-and-password/tsconfig.json delete mode 100644 examples/nextjs-pages/email-and-password/.eslintrc.json delete mode 100644 examples/nextjs-pages/email-and-password/.gitignore delete mode 100644 examples/nextjs-pages/email-and-password/.prettierignore delete mode 100644 examples/nextjs-pages/email-and-password/README.md delete mode 100644 examples/nextjs-pages/email-and-password/app.d.ts delete mode 100644 examples/nextjs-pages/email-and-password/auth/db.ts delete mode 100644 examples/nextjs-pages/email-and-password/auth/email.ts delete mode 100644 examples/nextjs-pages/email-and-password/auth/lucia.ts delete mode 100644 examples/nextjs-pages/email-and-password/auth/token.ts delete mode 100644 examples/nextjs-pages/email-and-password/next.config.js delete mode 100644 examples/nextjs-pages/email-and-password/package-lock.json delete mode 100644 examples/nextjs-pages/email-and-password/package.json delete mode 100644 examples/nextjs-pages/email-and-password/pages/_app.tsx delete mode 100644 examples/nextjs-pages/email-and-password/pages/api/email-verification/[token].ts delete mode 100644 examples/nextjs-pages/email-and-password/pages/api/email-verification/index.ts delete mode 100644 examples/nextjs-pages/email-and-password/pages/api/login.ts delete mode 100644 examples/nextjs-pages/email-and-password/pages/api/logout.ts delete mode 100644 examples/nextjs-pages/email-and-password/pages/api/password-reset/[token].ts delete mode 100644 examples/nextjs-pages/email-and-password/pages/api/password-reset/index.ts delete mode 100644 examples/nextjs-pages/email-and-password/pages/api/signup.ts delete mode 100644 examples/nextjs-pages/email-and-password/pages/email-verification.tsx delete mode 100644 examples/nextjs-pages/email-and-password/pages/index.tsx delete mode 100644 examples/nextjs-pages/email-and-password/pages/login.tsx delete mode 100644 examples/nextjs-pages/email-and-password/pages/password-reset/[token].tsx delete mode 100644 examples/nextjs-pages/email-and-password/pages/password-reset/index.tsx delete mode 100644 examples/nextjs-pages/email-and-password/pages/signup.tsx delete mode 100644 examples/nextjs-pages/email-and-password/public/favicon.ico delete mode 100644 examples/nextjs-pages/email-and-password/schema.sql delete mode 100644 examples/nextjs-pages/email-and-password/styles/globals.css delete mode 100644 examples/nextjs-pages/email-and-password/tsconfig.json delete mode 100644 examples/nextjs-pages/github-oauth/.env.example delete mode 100644 examples/nextjs-pages/github-oauth/.eslintrc.json delete mode 100644 examples/nextjs-pages/github-oauth/.gitignore delete mode 100644 examples/nextjs-pages/github-oauth/.prettierignore delete mode 100644 examples/nextjs-pages/github-oauth/README.md delete mode 100644 examples/nextjs-pages/github-oauth/app.d.ts delete mode 100644 examples/nextjs-pages/github-oauth/auth/lucia.ts delete mode 100644 examples/nextjs-pages/github-oauth/next.config.js delete mode 100644 examples/nextjs-pages/github-oauth/package-lock.json delete mode 100644 examples/nextjs-pages/github-oauth/package.json delete mode 100644 examples/nextjs-pages/github-oauth/pages/_app.tsx delete mode 100644 examples/nextjs-pages/github-oauth/pages/api/login/github/callback.ts delete mode 100644 examples/nextjs-pages/github-oauth/pages/api/login/github/index.ts delete mode 100644 examples/nextjs-pages/github-oauth/pages/api/logout.ts delete mode 100644 examples/nextjs-pages/github-oauth/pages/index.tsx delete mode 100644 examples/nextjs-pages/github-oauth/pages/login.tsx delete mode 100644 examples/nextjs-pages/github-oauth/public/favicon.ico delete mode 100644 examples/nextjs-pages/github-oauth/schema.sql delete mode 100644 examples/nextjs-pages/github-oauth/styles/globals.css delete mode 100644 examples/nextjs-pages/github-oauth/tsconfig.json delete mode 100644 examples/nextjs-pages/username-and-password/.eslintrc.json delete mode 100644 examples/nextjs-pages/username-and-password/.gitignore delete mode 100644 examples/nextjs-pages/username-and-password/.prettierignore delete mode 100644 examples/nextjs-pages/username-and-password/README.md delete mode 100644 examples/nextjs-pages/username-and-password/app.d.ts delete mode 100644 examples/nextjs-pages/username-and-password/auth/lucia.ts delete mode 100644 examples/nextjs-pages/username-and-password/next.config.js delete mode 100644 examples/nextjs-pages/username-and-password/package-lock.json delete mode 100644 examples/nextjs-pages/username-and-password/package.json delete mode 100644 examples/nextjs-pages/username-and-password/pages/_app.tsx delete mode 100644 examples/nextjs-pages/username-and-password/pages/api/login.ts delete mode 100644 examples/nextjs-pages/username-and-password/pages/api/logout.ts delete mode 100644 examples/nextjs-pages/username-and-password/pages/api/signup.ts delete mode 100644 examples/nextjs-pages/username-and-password/pages/index.tsx delete mode 100644 examples/nextjs-pages/username-and-password/pages/login.tsx delete mode 100644 examples/nextjs-pages/username-and-password/pages/signup.tsx delete mode 100644 examples/nextjs-pages/username-and-password/public/favicon.ico delete mode 100644 examples/nextjs-pages/username-and-password/schema.sql delete mode 100644 examples/nextjs-pages/username-and-password/styles/globals.css delete mode 100644 examples/nextjs-pages/username-and-password/tsconfig.json delete mode 100644 examples/nuxt/email-and-password/.gitignore delete mode 100644 examples/nuxt/email-and-password/.npmrc delete mode 100644 examples/nuxt/email-and-password/.prettierignore delete mode 100644 examples/nuxt/email-and-password/README.md delete mode 100644 examples/nuxt/email-and-password/app.vue delete mode 100644 examples/nuxt/email-and-password/composables/auth.ts delete mode 100644 examples/nuxt/email-and-password/middleware/auth.global.ts delete mode 100644 examples/nuxt/email-and-password/middleware/protected.ts delete mode 100644 examples/nuxt/email-and-password/nuxt.config.ts delete mode 100644 examples/nuxt/email-and-password/package.json delete mode 100644 examples/nuxt/email-and-password/pages/email-verification.vue delete mode 100644 examples/nuxt/email-and-password/pages/index.vue delete mode 100644 examples/nuxt/email-and-password/pages/login.vue delete mode 100644 examples/nuxt/email-and-password/pages/password-reset/[token].vue delete mode 100644 examples/nuxt/email-and-password/pages/password-reset/index.vue delete mode 100644 examples/nuxt/email-and-password/pages/signup.vue delete mode 100644 examples/nuxt/email-and-password/public/favicon.ico delete mode 100644 examples/nuxt/email-and-password/schema.sql delete mode 100644 examples/nuxt/email-and-password/server/api/email-verification/[token].get.ts delete mode 100644 examples/nuxt/email-and-password/server/api/email-verification/index.post.ts delete mode 100644 examples/nuxt/email-and-password/server/api/login.post.ts delete mode 100644 examples/nuxt/email-and-password/server/api/logout.post.ts delete mode 100644 examples/nuxt/email-and-password/server/api/password-reset/[token].post.ts delete mode 100644 examples/nuxt/email-and-password/server/api/password-reset/index.post.ts delete mode 100644 examples/nuxt/email-and-password/server/api/signup.post.ts delete mode 100644 examples/nuxt/email-and-password/server/api/user.get.ts delete mode 100644 examples/nuxt/email-and-password/server/app.d.ts delete mode 100644 examples/nuxt/email-and-password/server/tsconfig.json delete mode 100644 examples/nuxt/email-and-password/server/utils/db.ts delete mode 100644 examples/nuxt/email-and-password/server/utils/email.ts delete mode 100644 examples/nuxt/email-and-password/server/utils/lucia.ts delete mode 100644 examples/nuxt/email-and-password/server/utils/token.ts delete mode 100644 examples/nuxt/email-and-password/tsconfig.json delete mode 100644 examples/nuxt/github-oauth/.env.example delete mode 100644 examples/nuxt/github-oauth/.gitignore delete mode 100644 examples/nuxt/github-oauth/.npmrc delete mode 100644 examples/nuxt/github-oauth/.prettierignore delete mode 100644 examples/nuxt/github-oauth/README.md delete mode 100644 examples/nuxt/github-oauth/app.vue delete mode 100644 examples/nuxt/github-oauth/composables/auth.ts delete mode 100644 examples/nuxt/github-oauth/middleware/auth.global.ts delete mode 100644 examples/nuxt/github-oauth/middleware/protected.ts delete mode 100644 examples/nuxt/github-oauth/nuxt.config.ts delete mode 100644 examples/nuxt/github-oauth/package.json delete mode 100644 examples/nuxt/github-oauth/pages/index.vue delete mode 100644 examples/nuxt/github-oauth/pages/login.vue delete mode 100644 examples/nuxt/github-oauth/public/favicon.ico delete mode 100644 examples/nuxt/github-oauth/schema.sql delete mode 100644 examples/nuxt/github-oauth/server/api/login/github/callback.get.ts delete mode 100644 examples/nuxt/github-oauth/server/api/login/github/index.get.ts delete mode 100644 examples/nuxt/github-oauth/server/api/logout.post.ts delete mode 100644 examples/nuxt/github-oauth/server/api/user.get.ts delete mode 100644 examples/nuxt/github-oauth/server/app.d.ts delete mode 100644 examples/nuxt/github-oauth/server/tsconfig.json delete mode 100644 examples/nuxt/github-oauth/server/utils/lucia.ts delete mode 100644 examples/nuxt/github-oauth/tsconfig.json delete mode 100644 examples/nuxt/username-and-password/.gitignore delete mode 100644 examples/nuxt/username-and-password/.npmrc delete mode 100644 examples/nuxt/username-and-password/.prettierignore delete mode 100644 examples/nuxt/username-and-password/README.md delete mode 100644 examples/nuxt/username-and-password/app.vue delete mode 100644 examples/nuxt/username-and-password/composables/auth.ts delete mode 100644 examples/nuxt/username-and-password/middleware/auth.global.ts delete mode 100644 examples/nuxt/username-and-password/middleware/protected.ts delete mode 100644 examples/nuxt/username-and-password/nuxt.config.ts delete mode 100644 examples/nuxt/username-and-password/package.json delete mode 100644 examples/nuxt/username-and-password/pages/index.vue delete mode 100644 examples/nuxt/username-and-password/pages/login.vue delete mode 100644 examples/nuxt/username-and-password/pages/signup.vue delete mode 100644 examples/nuxt/username-and-password/public/favicon.ico delete mode 100644 examples/nuxt/username-and-password/schema.sql delete mode 100644 examples/nuxt/username-and-password/server/api/login.post.ts delete mode 100644 examples/nuxt/username-and-password/server/api/logout.post.ts delete mode 100644 examples/nuxt/username-and-password/server/api/signup.post.ts delete mode 100644 examples/nuxt/username-and-password/server/api/user.get.ts delete mode 100644 examples/nuxt/username-and-password/server/app.d.ts delete mode 100644 examples/nuxt/username-and-password/server/tsconfig.json delete mode 100644 examples/nuxt/username-and-password/server/utils/lucia.ts delete mode 100644 examples/nuxt/username-and-password/tsconfig.json delete mode 100644 examples/other/login-throttling-device-cookie/README.md delete mode 100644 examples/other/login-throttling-device-cookie/package.json delete mode 100644 examples/other/login-throttling-device-cookie/src/index.html delete mode 100644 examples/other/login-throttling-device-cookie/src/index.ts delete mode 100644 examples/other/login-throttling/README.md delete mode 100644 examples/other/login-throttling/package.json delete mode 100644 examples/other/login-throttling/src/index.html delete mode 100644 examples/other/login-throttling/src/index.ts delete mode 100644 examples/solidstart/github-oauth/.env.example delete mode 100644 examples/solidstart/github-oauth/.gitignore delete mode 100644 examples/solidstart/github-oauth/README.md delete mode 100644 examples/solidstart/github-oauth/package.json delete mode 100644 examples/solidstart/github-oauth/public/favicon.ico delete mode 100644 examples/solidstart/github-oauth/schema.sql delete mode 100644 examples/solidstart/github-oauth/src/app.d.ts delete mode 100644 examples/solidstart/github-oauth/src/auth/lucia.ts delete mode 100644 examples/solidstart/github-oauth/src/entry-client.tsx delete mode 100644 examples/solidstart/github-oauth/src/entry-server.tsx delete mode 100644 examples/solidstart/github-oauth/src/root.css delete mode 100644 examples/solidstart/github-oauth/src/root.tsx delete mode 100644 examples/solidstart/github-oauth/src/routes/[...404].tsx delete mode 100644 examples/solidstart/github-oauth/src/routes/index.tsx delete mode 100644 examples/solidstart/github-oauth/src/routes/login/github/callback.ts delete mode 100644 examples/solidstart/github-oauth/src/routes/login/github/index.ts delete mode 100644 examples/solidstart/github-oauth/src/routes/login/index.tsx delete mode 100644 examples/solidstart/github-oauth/tsconfig.json delete mode 100644 examples/solidstart/github-oauth/vite.config.ts delete mode 100644 examples/solidstart/username-and-password/.gitignore delete mode 100644 examples/solidstart/username-and-password/README.md delete mode 100644 examples/solidstart/username-and-password/package.json delete mode 100644 examples/solidstart/username-and-password/public/favicon.ico delete mode 100644 examples/solidstart/username-and-password/schema.sql delete mode 100644 examples/solidstart/username-and-password/src/app.d.ts delete mode 100644 examples/solidstart/username-and-password/src/auth/lucia.ts delete mode 100644 examples/solidstart/username-and-password/src/entry-client.tsx delete mode 100644 examples/solidstart/username-and-password/src/entry-server.tsx delete mode 100644 examples/solidstart/username-and-password/src/root.css delete mode 100644 examples/solidstart/username-and-password/src/root.tsx delete mode 100644 examples/solidstart/username-and-password/src/routes/[...404].tsx delete mode 100644 examples/solidstart/username-and-password/src/routes/index.tsx delete mode 100644 examples/solidstart/username-and-password/src/routes/login.tsx delete mode 100644 examples/solidstart/username-and-password/src/routes/signup.tsx delete mode 100644 examples/solidstart/username-and-password/tsconfig.json delete mode 100644 examples/solidstart/username-and-password/vite.config.ts delete mode 100644 examples/sveltekit/email-and-password/.eslintignore delete mode 100644 examples/sveltekit/email-and-password/.eslintrc.cjs delete mode 100644 examples/sveltekit/email-and-password/.gitignore delete mode 100644 examples/sveltekit/email-and-password/.npmrc delete mode 100644 examples/sveltekit/email-and-password/.prettierignore delete mode 100644 examples/sveltekit/email-and-password/.prettierrc delete mode 100644 examples/sveltekit/email-and-password/README.md delete mode 100644 examples/sveltekit/email-and-password/package.json delete mode 100644 examples/sveltekit/email-and-password/schema.sql delete mode 100644 examples/sveltekit/email-and-password/src/app.css delete mode 100644 examples/sveltekit/email-and-password/src/app.d.ts delete mode 100644 examples/sveltekit/email-and-password/src/app.html delete mode 100644 examples/sveltekit/email-and-password/src/hooks.server.ts delete mode 100644 examples/sveltekit/email-and-password/src/lib/server/db.ts delete mode 100644 examples/sveltekit/email-and-password/src/lib/server/email.ts delete mode 100644 examples/sveltekit/email-and-password/src/lib/server/lucia.ts delete mode 100644 examples/sveltekit/email-and-password/src/lib/server/token.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/+layout.svelte delete mode 100644 examples/sveltekit/email-and-password/src/routes/+page.server.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/+page.svelte delete mode 100644 examples/sveltekit/email-and-password/src/routes/email-verification/+page.server.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/email-verification/+page.svelte delete mode 100644 examples/sveltekit/email-and-password/src/routes/email-verification/[token]/+server.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/login/+page.server.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/login/+page.svelte delete mode 100644 examples/sveltekit/email-and-password/src/routes/password-reset/+page.server.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/password-reset/+page.svelte delete mode 100644 examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.server.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.svelte delete mode 100644 examples/sveltekit/email-and-password/src/routes/signup/+page.server.ts delete mode 100644 examples/sveltekit/email-and-password/src/routes/signup/+page.svelte delete mode 100644 examples/sveltekit/email-and-password/static/favicon.png delete mode 100644 examples/sveltekit/email-and-password/svelte.config.js delete mode 100644 examples/sveltekit/email-and-password/tsconfig.json delete mode 100644 examples/sveltekit/email-and-password/vite.config.ts delete mode 100644 examples/sveltekit/github-oauth/.env.example delete mode 100644 examples/sveltekit/github-oauth/.eslintignore delete mode 100644 examples/sveltekit/github-oauth/.eslintrc.cjs delete mode 100644 examples/sveltekit/github-oauth/.gitignore delete mode 100644 examples/sveltekit/github-oauth/.npmrc delete mode 100644 examples/sveltekit/github-oauth/.prettierignore delete mode 100644 examples/sveltekit/github-oauth/.prettierrc delete mode 100644 examples/sveltekit/github-oauth/README.md delete mode 100644 examples/sveltekit/github-oauth/package.json delete mode 100644 examples/sveltekit/github-oauth/schema.sql delete mode 100644 examples/sveltekit/github-oauth/src/app.css delete mode 100644 examples/sveltekit/github-oauth/src/app.d.ts delete mode 100644 examples/sveltekit/github-oauth/src/app.html delete mode 100644 examples/sveltekit/github-oauth/src/hooks.server.ts delete mode 100644 examples/sveltekit/github-oauth/src/lib/server/lucia.ts delete mode 100644 examples/sveltekit/github-oauth/src/routes/+layout.svelte delete mode 100644 examples/sveltekit/github-oauth/src/routes/+page.server.ts delete mode 100644 examples/sveltekit/github-oauth/src/routes/+page.svelte delete mode 100644 examples/sveltekit/github-oauth/src/routes/login/+page.server.ts delete mode 100644 examples/sveltekit/github-oauth/src/routes/login/+page.svelte delete mode 100644 examples/sveltekit/github-oauth/src/routes/login/github/+server.ts delete mode 100644 examples/sveltekit/github-oauth/src/routes/login/github/callback/+server.ts delete mode 100644 examples/sveltekit/github-oauth/static/favicon.png delete mode 100644 examples/sveltekit/github-oauth/svelte.config.js delete mode 100644 examples/sveltekit/github-oauth/tsconfig.json delete mode 100644 examples/sveltekit/github-oauth/vite.config.ts delete mode 100644 examples/sveltekit/username-and-password/.eslintignore delete mode 100644 examples/sveltekit/username-and-password/.eslintrc.cjs delete mode 100644 examples/sveltekit/username-and-password/.gitignore delete mode 100644 examples/sveltekit/username-and-password/.npmrc delete mode 100644 examples/sveltekit/username-and-password/.prettierignore delete mode 100644 examples/sveltekit/username-and-password/.prettierrc delete mode 100644 examples/sveltekit/username-and-password/README.md delete mode 100644 examples/sveltekit/username-and-password/package.json delete mode 100644 examples/sveltekit/username-and-password/schema.sql delete mode 100644 examples/sveltekit/username-and-password/src/app.css delete mode 100644 examples/sveltekit/username-and-password/src/app.d.ts delete mode 100644 examples/sveltekit/username-and-password/src/app.html delete mode 100644 examples/sveltekit/username-and-password/src/hooks.server.ts delete mode 100644 examples/sveltekit/username-and-password/src/lib/server/lucia.ts delete mode 100644 examples/sveltekit/username-and-password/src/routes/+layout.svelte delete mode 100644 examples/sveltekit/username-and-password/src/routes/+page.server.ts delete mode 100644 examples/sveltekit/username-and-password/src/routes/+page.svelte delete mode 100644 examples/sveltekit/username-and-password/src/routes/login/+page.server.ts delete mode 100644 examples/sveltekit/username-and-password/src/routes/login/+page.svelte delete mode 100644 examples/sveltekit/username-and-password/src/routes/signup/+page.server.ts delete mode 100644 examples/sveltekit/username-and-password/src/routes/signup/+page.svelte delete mode 100644 examples/sveltekit/username-and-password/static/favicon.png delete mode 100644 examples/sveltekit/username-and-password/svelte.config.js delete mode 100644 examples/sveltekit/username-and-password/tsconfig.json delete mode 100644 examples/sveltekit/username-and-password/vite.config.ts delete mode 100644 examples/tauri/github-oauth/README.md delete mode 100644 examples/tauri/github-oauth/app/.gitignore delete mode 100644 examples/tauri/github-oauth/app/index.html delete mode 100644 examples/tauri/github-oauth/app/package.json delete mode 100644 examples/tauri/github-oauth/app/src-tauri/.gitignore delete mode 100644 examples/tauri/github-oauth/app/src-tauri/Cargo.toml delete mode 100644 examples/tauri/github-oauth/app/src-tauri/build.rs delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/128x128.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/128x128@2x.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/32x32.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square107x107Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square142x142Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square150x150Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square284x284Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square30x30Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square310x310Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square44x44Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square71x71Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/Square89x89Logo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/StoreLogo.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/icon.icns delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/icon.ico delete mode 100644 examples/tauri/github-oauth/app/src-tauri/icons/icon.png delete mode 100644 examples/tauri/github-oauth/app/src-tauri/src/main.rs delete mode 100644 examples/tauri/github-oauth/app/src-tauri/tauri.conf.json delete mode 100644 examples/tauri/github-oauth/app/src/main.ts delete mode 100644 examples/tauri/github-oauth/app/src/styles.css delete mode 100644 examples/tauri/github-oauth/app/tsconfig.json delete mode 100644 examples/tauri/github-oauth/app/vite.config.ts delete mode 100644 examples/tauri/github-oauth/server/.env.example delete mode 100644 examples/tauri/github-oauth/server/.gitignore delete mode 100644 examples/tauri/github-oauth/server/package.json delete mode 100644 examples/tauri/github-oauth/server/src/app.d.ts delete mode 100644 examples/tauri/github-oauth/server/src/auth.ts delete mode 100644 examples/tauri/github-oauth/server/src/index.ts delete mode 100644 examples/tauri/github-oauth/server/src/schema.sql diff --git a/README.md b/README.md index fc3844168..9b9f30380 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,12 @@ const sessionCookie = auth.createSessionCookie(session); **[Join the Discord server!](https://discord.gg/PwrK3kpVR3)** -**[Changelog](https://github.com/pilcrowOnPaper/lucia/blob/main/packages/lucia/CHANGELOG.md)** +**[Examples](https://github.com/lucia-auth/examples)** **[Contributing](https://lucia-auth.com/start-here/contributing)** +**[Changelog](https://github.com/pilcrowOnPaper/lucia/blob/main/packages/lucia/CHANGELOG.md)** + ## Installation ``` diff --git a/documentation/content/guidebook/email-verification-links/$express.md b/documentation/content/guidebook/email-verification-links/$express.md index b06ca22e9..a8822d21a 100644 --- a/documentation/content/guidebook/email-verification-links/$express.md +++ b/documentation/content/guidebook/email-verification-links/$express.md @@ -9,13 +9,13 @@ If you're new to Lucia, we recommend starting with [Sign in with username and pa ### Clone project -You can get started immediately by cloning the [Express example](https://github.com/lucia-auth/lucia/tree/main/examples/express/email-and-password) from the repository. +You can get started immediately by cloning the [Express example](https://github.com/lucia-auth/examples/tree/main/express/email-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/express/email-and-password +npx degit lucia-auth/examples/express/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/express/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/express/email-and-password). ## Database diff --git a/documentation/content/guidebook/email-verification-links/$nextjs-app.md b/documentation/content/guidebook/email-verification-links/$nextjs-app.md index f82d8667e..4b875e7da 100644 --- a/documentation/content/guidebook/email-verification-links/$nextjs-app.md +++ b/documentation/content/guidebook/email-verification-links/$nextjs-app.md @@ -18,13 +18,13 @@ It will also have a route to handle verification links. ### Clone project -You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-app/email-and-password) from the repository. +You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-app/email-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/nextjs-app/email-and-password +npx degit lucia-auth/examples/nextjs-app/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-app/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-app/email-and-password). ## Database diff --git a/documentation/content/guidebook/email-verification-links/$nextjs-pages.md b/documentation/content/guidebook/email-verification-links/$nextjs-pages.md index 5a38e7195..bac3520a1 100644 --- a/documentation/content/guidebook/email-verification-links/$nextjs-pages.md +++ b/documentation/content/guidebook/email-verification-links/$nextjs-pages.md @@ -18,13 +18,13 @@ It will also have a route to handle verification links. ### Clone project -You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-pages/email-and-password) from the repository. +You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-pages/email-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/nextjs-pages/email-and-password +npx degit lucia-auth/examples/nextjs-pages/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-pages/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-pages/email-and-password). ## Database diff --git a/documentation/content/guidebook/email-verification-links/$nuxt.md b/documentation/content/guidebook/email-verification-links/$nuxt.md index 9bf60c013..1976364b9 100644 --- a/documentation/content/guidebook/email-verification-links/$nuxt.md +++ b/documentation/content/guidebook/email-verification-links/$nuxt.md @@ -18,13 +18,13 @@ It will also have a route to handle verification links. ### Clone project -You can get started immediately by cloning the [Nuxt example](https://github.com/lucia-auth/lucia/tree/main/examples/nuxt/email-and-password) from the repository. +You can get started immediately by cloning the [Nuxt example](https://github.com/lucia-auth/examples/tree/main/nuxt/email-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/nuxt/email-and-password +npx degit lucia-auth/examples/nuxt/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nuxt/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nuxt/email-and-password). ## Database diff --git a/documentation/content/guidebook/email-verification-links/$sveltekit.md b/documentation/content/guidebook/email-verification-links/$sveltekit.md index 95df3df7b..b5aafac50 100644 --- a/documentation/content/guidebook/email-verification-links/$sveltekit.md +++ b/documentation/content/guidebook/email-verification-links/$sveltekit.md @@ -18,13 +18,13 @@ It will also have a route to handle verification links. ### Clone project -You can get started immediately by cloning the [SvelteKit example](https://github.com/lucia-auth/lucia/tree/main/examples/sveltekit/email-and-password) from the repository. +You can get started immediately by cloning the [SvelteKit example](https://github.com/lucia-auth/examples/tree/main/sveltekit/email-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/sveltekit/email-and-password +npx degit lucia-auth/examples/sveltekit/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/sveltekit/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/sveltekit/email-and-password). ## Database diff --git a/documentation/content/guidebook/github-oauth-native/electron.md b/documentation/content/guidebook/github-oauth-native/electron.md index 5a18049a6..b8a019188 100644 --- a/documentation/content/guidebook/github-oauth-native/electron.md +++ b/documentation/content/guidebook/github-oauth-native/electron.md @@ -11,13 +11,13 @@ To send the session token (ie. session id) from the server back to our applicati ### Clone project -You can get started immediately by cloning the [example](https://github.com/lucia-auth/lucia/tree/main/examples/electron/github-oauth) from the repository. +You can get started immediately by cloning the [example](https://github.com/lucia-auth/examples/tree/main/electron/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/electron/github-oauth +npx degit lucia-auth/examples/electron/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/electron/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/electron/github-oauth). ## Server diff --git a/documentation/content/guidebook/github-oauth-native/expo.md b/documentation/content/guidebook/github-oauth-native/expo.md index 41b77bb53..32a8dabf2 100644 --- a/documentation/content/guidebook/github-oauth-native/expo.md +++ b/documentation/content/guidebook/github-oauth-native/expo.md @@ -11,13 +11,13 @@ To send the session token (ie. session id) from the server back to our applicati ### Clone project -You can get started immediately by cloning the [example](https://github.com/lucia-auth/lucia/tree/main/examples/expo/github-oauth) from the repository. +You can get started immediately by cloning the [example](https://github.com/lucia-auth/examples/tree/main/expo/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/expo/github-oauth +npx degit lucia-auth/examples/expo/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/expo/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/expo/github-oauth). ## Server diff --git a/documentation/content/guidebook/github-oauth-native/tauri.md b/documentation/content/guidebook/github-oauth-native/tauri.md index 6b3608b3a..9b117b1eb 100644 --- a/documentation/content/guidebook/github-oauth-native/tauri.md +++ b/documentation/content/guidebook/github-oauth-native/tauri.md @@ -13,13 +13,13 @@ The strategy we'll be using is to create a super basic local server in the backg ### Clone project -You can get started immediately by cloning the [example](https://github.com/lucia-auth/lucia/tree/main/examples/tauri/github-oauth) from the repository. +You can get started immediately by cloning the [example](https://github.com/lucia-auth/examples/tree/main/tauri/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/tauri/github-oauth +npx degit lucia-auth/examples/tauri/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/tauri/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/tauri/github-oauth). ## Server diff --git a/documentation/content/guidebook/github-oauth/$astro.md b/documentation/content/guidebook/github-oauth/$astro.md index de76d2e03..185b2ba83 100644 --- a/documentation/content/guidebook/github-oauth/$astro.md +++ b/documentation/content/guidebook/github-oauth/$astro.md @@ -15,13 +15,13 @@ As a general overview of OAuth, the user is redirected to github.com to be authe ### Clone project -You can get started immediately by cloning the [Astro example](https://github.com/lucia-auth/lucia/tree/main/examples/astro/github-oauth) from the repository. +You can get started immediately by cloning the [Astro example](https://github.com/lucia-auth/examples/tree/main/astro/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/astro/github-oauth +npx degit lucia-auth/examples/astro/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/astro/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/astro/github-oauth). ## Create an OAuth app diff --git a/documentation/content/guidebook/github-oauth/$express.md b/documentation/content/guidebook/github-oauth/$express.md index f2365f9d6..9fbc8d167 100644 --- a/documentation/content/guidebook/github-oauth/$express.md +++ b/documentation/content/guidebook/github-oauth/$express.md @@ -9,13 +9,13 @@ This guide will cover how to implement GitHub OAuth using Lucia in Express with ### Clone project -You can get started immediately by cloning the [Express example](https://github.com/lucia-auth/lucia/tree/main/examples/express/github-oauth) from the repository. +You can get started immediately by cloning the [Express example](https://github.com/lucia-auth/examples/tree/main/express/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/express/github-oauth +npx degit lucia-auth/examples/express/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/express/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/express/github-oauth). ## Create an OAuth app diff --git a/documentation/content/guidebook/github-oauth/$nextjs-app.md b/documentation/content/guidebook/github-oauth/$nextjs-app.md index b704e00ae..c7b70154d 100644 --- a/documentation/content/guidebook/github-oauth/$nextjs-app.md +++ b/documentation/content/guidebook/github-oauth/$nextjs-app.md @@ -15,13 +15,13 @@ As a general overview of OAuth, the user is redirected to github.com to be authe ### Clone project -You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-app/github-oauth) from the repository. +You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-app/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/nextjs-app/github-oauth +npx degit lucia-auth/examples/nextjs-app/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-app/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-app/github-oauth). ## Create an OAuth app diff --git a/documentation/content/guidebook/github-oauth/$nextjs-pages.md b/documentation/content/guidebook/github-oauth/$nextjs-pages.md index 1fb29809a..d912bd9d8 100644 --- a/documentation/content/guidebook/github-oauth/$nextjs-pages.md +++ b/documentation/content/guidebook/github-oauth/$nextjs-pages.md @@ -15,13 +15,13 @@ As a general overview of OAuth, the user is redirected to github.com to be authe ### Clone project -You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-pages/github-oauth) from the repository. +You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-pages/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/nextjs-pages/github-oauth +npx degit lucia-auth/examples/nextjs-pages/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-pages/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-pages/github-oauth). ## Create an OAuth app diff --git a/documentation/content/guidebook/github-oauth/$nuxt.md b/documentation/content/guidebook/github-oauth/$nuxt.md index 8f8ad7ac2..73c10e453 100644 --- a/documentation/content/guidebook/github-oauth/$nuxt.md +++ b/documentation/content/guidebook/github-oauth/$nuxt.md @@ -15,13 +15,13 @@ As a general overview of OAuth, the user is redirected to github.com to be authe ### Clone project -You can get started immediately by cloning the [Nuxt example](https://github.com/lucia-auth/lucia/tree/main/examples/nuxt/github-oauth) from the repository. +You can get started immediately by cloning the [Nuxt example](https://github.com/lucia-auth/examples/tree/main/nuxt/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/nuxt/github-oauth +npx degit lucia-auth/examples/nuxt/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nuxt/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nuxt/github-oauth). ## Create an OAuth app diff --git a/documentation/content/guidebook/github-oauth/$solidstart.md b/documentation/content/guidebook/github-oauth/$solidstart.md index 19496ba5e..d4a939f4c 100644 --- a/documentation/content/guidebook/github-oauth/$solidstart.md +++ b/documentation/content/guidebook/github-oauth/$solidstart.md @@ -15,13 +15,13 @@ As a general overview of OAuth, the user is redirected to github.com to be authe ### Clone project -You can get started immediately by cloning the [SolidStart example](https://github.com/lucia-auth/lucia/tree/main/examples/solidstart/github-oauth) from the repository. +You can get started immediately by cloning the [SolidStart example](https://github.com/lucia-auth/examples/tree/main/solidstart/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/solidstart/github-oauth +npx degit lucia-auth/examples/solidstart/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/solidstart/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/solidstart/github-oauth). ## Create an OAuth app diff --git a/documentation/content/guidebook/github-oauth/$sveltekit.md b/documentation/content/guidebook/github-oauth/$sveltekit.md index 16de2b191..9dfb11dd0 100644 --- a/documentation/content/guidebook/github-oauth/$sveltekit.md +++ b/documentation/content/guidebook/github-oauth/$sveltekit.md @@ -15,13 +15,13 @@ As a general overview of OAuth, the user is redirected to github.com to be authe ### Clone project -You can get started immediately by cloning the [SvelteKit example](https://github.com/lucia-auth/lucia/tree/main/examples/sveltekit/github-oauth) from the repository. +You can get started immediately by cloning the [SvelteKit example](https://github.com/lucia-auth/examples/tree/main/sveltekit/github-oauth) from the repository. ``` -npx degit lucia-auth/lucia/examples/sveltekit/github-oauth +npx degit lucia-auth/examples/sveltekit/github-oauth ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/sveltekit/github-oauth). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/sveltekit/github-oauth). ## Create an OAuth app diff --git a/documentation/content/guidebook/login-throttling.md b/documentation/content/guidebook/login-throttling.md index 1564914e9..d0580ea4e 100644 --- a/documentation/content/guidebook/login-throttling.md +++ b/documentation/content/guidebook/login-throttling.md @@ -9,7 +9,7 @@ One simple approach is to use exponential backoff to increase the timeout on eve ## Basic example -The following example stores the attempts in memory. You can of course use a regular database but running it in within a transaction is recommended. The timeout doubles on every failed login attempt until the user is successfully authenticated. A [demo](https://github.com/lucia-auth/lucia/tree/main/examples/other/login-throttling) is available in the repository. +The following example stores the attempts in memory. You can of course use a regular database but running it in within a transaction is recommended. The timeout doubles on every failed login attempt until the user is successfully authenticated. A [demo](https://github.com/lucia-auth/examples/tree/main/other/login-throttling) is available in the repository. ```ts const loginTimeout = new Map< @@ -51,7 +51,7 @@ try { One issue with the basic example above is that a valid user may be locked out if an attacker attempts to sign in. This is of course much better than being susceptible to brute force attacks, but one way to avoid it is to remember users/devices that signed in once and skipping the timeout for the first few attempts. -The following example stores the attempts and valid device cookies in memory. When a user is authenticated, a new device cookie is created. This cookie allows the user to bypass the throttling for the first 5 login attempts if they sign out. A [demo](https://github.com/lucia-auth/lucia/tree/main/examples/other/login-throtting-device-cookie) is available in the repository. +The following example stores the attempts and valid device cookies in memory. When a user is authenticated, a new device cookie is created. This cookie allows the user to bypass the throttling for the first 5 login attempts if they sign out. A [demo](https://github.com/lucia-auth/examples/tree/main/other/login-throtting-device-cookie) is available in the repository. ```ts const loginTimeout = new Map< diff --git a/documentation/content/guidebook/password-reset-link/$express.md b/documentation/content/guidebook/password-reset-link/$express.md index 7e8d8656f..81f95419a 100644 --- a/documentation/content/guidebook/password-reset-link/$express.md +++ b/documentation/content/guidebook/password-reset-link/$express.md @@ -25,13 +25,13 @@ export type Auth = typeof auth; ### Clone project -The [email and password Express example](https://github.com/lucia-auth/lucia/tree/main/examples/express/email-and-password) includes password reset. +The [email and password Express example](https://github.com/lucia-auth/examples/tree/main/express/email-and-password) includes password reset. ``` -npx degit lucia-auth/lucia/examples/express/email-and-password +npx degit lucia-auth/examples/express/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/express/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/express/email-and-password). ## Database diff --git a/documentation/content/guidebook/password-reset-link/$nextjs-app.md b/documentation/content/guidebook/password-reset-link/$nextjs-app.md index 5b232a49d..7c3d893b9 100644 --- a/documentation/content/guidebook/password-reset-link/$nextjs-app.md +++ b/documentation/content/guidebook/password-reset-link/$nextjs-app.md @@ -28,13 +28,13 @@ export type Auth = typeof auth; ### Clone project -The [email and password Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-app/email-and-password) includes password reset. +The [email and password Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-app/email-and-password) includes password reset. ``` -npx degit lucia-auth/lucia/examples/nextjs-app/email-and-password +npx degit lucia-auth/examples/nextjs-app/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-app/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-app/email-and-password). ## Database diff --git a/documentation/content/guidebook/password-reset-link/$nextjs-pages.md b/documentation/content/guidebook/password-reset-link/$nextjs-pages.md index 1dd392dc1..23b44561e 100644 --- a/documentation/content/guidebook/password-reset-link/$nextjs-pages.md +++ b/documentation/content/guidebook/password-reset-link/$nextjs-pages.md @@ -25,13 +25,13 @@ export type Auth = typeof auth; ### Clone project -The [email and password Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-pages/email-and-password) includes password reset. +The [email and password Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-pages/email-and-password) includes password reset. ``` -npx degit lucia-auth/lucia/examples/nextjs-pages/email-and-password +npx degit lucia-auth/examples/nextjs-pages/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-pages/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-pages/email-and-password). ## Database diff --git a/documentation/content/guidebook/password-reset-link/$nuxt.md b/documentation/content/guidebook/password-reset-link/$nuxt.md index 3eed98ef3..e5024a89f 100644 --- a/documentation/content/guidebook/password-reset-link/$nuxt.md +++ b/documentation/content/guidebook/password-reset-link/$nuxt.md @@ -25,13 +25,13 @@ export type Auth = typeof auth; ### Clone project -The [email and password Nuxt example](https://github.com/lucia-auth/lucia/tree/main/examples/nuxt/email-and-password) includes password reset. +The [email and password Nuxt example](https://github.com/lucia-auth/examples/tree/main/nuxt/email-and-password) includes password reset. ``` -npx degit lucia-auth/lucia/examples/nuxt/email-and-password +npx degit lucia-auth/examples/nuxt/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nuxt/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nuxt/email-and-password). ## Database diff --git a/documentation/content/guidebook/password-reset-link/$sveltekit.md b/documentation/content/guidebook/password-reset-link/$sveltekit.md index 2cae032bc..86c8ca261 100644 --- a/documentation/content/guidebook/password-reset-link/$sveltekit.md +++ b/documentation/content/guidebook/password-reset-link/$sveltekit.md @@ -25,13 +25,13 @@ export type Auth = typeof auth; ### Clone project -The [email and password SvelteKit example](https://github.com/lucia-auth/lucia/tree/main/examples/sveltekit/email-and-password) includes password reset. +The [email and password SvelteKit example](https://github.com/lucia-auth/examples/tree/main/sveltekit/email-and-password) includes password reset. ``` -npx degit lucia-auth/lucia/examples/sveltekit/email-and-password +npx degit lucia-auth/examples/sveltekit/email-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/sveltekit/email-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/sveltekit/email-and-password). ## Database diff --git a/documentation/content/guidebook/sign-in-with-username-and-password/$astro.md b/documentation/content/guidebook/sign-in-with-username-and-password/$astro.md index ad44725af..672e50ec2 100644 --- a/documentation/content/guidebook/sign-in-with-username-and-password/$astro.md +++ b/documentation/content/guidebook/sign-in-with-username-and-password/$astro.md @@ -13,13 +13,13 @@ This guide will cover how to implement a simple username and password authentica ### Clone project -You can get started immediately by cloning the [Astro example](https://github.com/lucia-auth/lucia/tree/main/examples/astro/username-and-password) from the repository. +You can get started immediately by cloning the [Astro example](https://github.com/lucia-auth/examples/tree/main/astro/username-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/astro/username-and-password +npx degit lucia-auth/examples/astro/username-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/astro/username-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/astro/username-and-password). ## Update your database diff --git a/documentation/content/guidebook/sign-in-with-username-and-password/$express.md b/documentation/content/guidebook/sign-in-with-username-and-password/$express.md index 8ec76b618..cffbfd1bb 100644 --- a/documentation/content/guidebook/sign-in-with-username-and-password/$express.md +++ b/documentation/content/guidebook/sign-in-with-username-and-password/$express.md @@ -9,13 +9,13 @@ This guide will cover how to implement a simple username and password authentica ### Clone project -You can get started immediately by cloning the [Express example](https://github.com/lucia-auth/lucia/tree/main/examples/express/username-and-password) from the repository. +You can get started immediately by cloning the [Express example](https://github.com/lucia-auth/examples/tree/main/express/username-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/express/username-and-password +npx degit lucia-auth/examples/express/username-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/express/username-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/express/username-and-password). ## Update your database diff --git a/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-app.md b/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-app.md index 56731423b..07cba7df2 100644 --- a/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-app.md +++ b/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-app.md @@ -13,13 +13,13 @@ This guide will cover how to implement a simple username and password authentica ### Clone project -You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-app/username-and-password) from the repository. +You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-app/username-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/nextjs-app/username-and-password +npx degit lucia-auth/examples/nextjs-app/username-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-app/username-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-app/username-and-password). ## Update your database diff --git a/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-pages.md b/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-pages.md index 46c00c84f..569b96d64 100644 --- a/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-pages.md +++ b/documentation/content/guidebook/sign-in-with-username-and-password/$nextjs-pages.md @@ -13,13 +13,13 @@ This guide will cover how to implement a simple username and password authentica ### Clone project -You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/lucia/tree/main/examples/nextjs-pages/username-and-password) from the repository. +You can get started immediately by cloning the [Next.js example](https://github.com/lucia-auth/examples/tree/main/nextjs-pages/username-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/nextjs-pages/username-and-password +npx degit lucia-auth/examples/nextjs-pages/username-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nextjs-pages/username-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nextjs-pages/username-and-password). ## Update your database diff --git a/documentation/content/guidebook/sign-in-with-username-and-password/$nuxt.md b/documentation/content/guidebook/sign-in-with-username-and-password/$nuxt.md index 3210b04bb..0164edf21 100644 --- a/documentation/content/guidebook/sign-in-with-username-and-password/$nuxt.md +++ b/documentation/content/guidebook/sign-in-with-username-and-password/$nuxt.md @@ -13,13 +13,13 @@ This guide will cover how to implement a simple username and password authentica ### Clone project -You can get started immediately by cloning the [Nuxt example](https://github.com/lucia-auth/lucia/tree/main/examples/nuxt/username-and-password) from the repository. +You can get started immediately by cloning the [Nuxt example](https://github.com/lucia-auth/examples/tree/main/nuxt/username-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/nuxt/username-and-password +npx degit lucia-auth/examples/nuxt/username-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/nuxt/username-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/nuxt/username-and-password). ## Update your database diff --git a/documentation/content/guidebook/sign-in-with-username-and-password/$solidstart.md b/documentation/content/guidebook/sign-in-with-username-and-password/$solidstart.md index 742a4eb14..7414eef94 100644 --- a/documentation/content/guidebook/sign-in-with-username-and-password/$solidstart.md +++ b/documentation/content/guidebook/sign-in-with-username-and-password/$solidstart.md @@ -13,13 +13,13 @@ This guide will cover how to implement a simple username and password authentica ### Clone project -You can get started immediately by cloning the [SolidStart example](https://github.com/lucia-auth/lucia/tree/main/examples/solidstart/username-and-password) from the repository. +You can get started immediately by cloning the [SolidStart example](https://github.com/lucia-auth/examples/tree/main/solidstart/username-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/solidstart/username-and-password +npx degit lucia-auth/examples/solidstart/username-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/solidstart/username-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/solidstart/username-and-password). ## Update your database diff --git a/documentation/content/guidebook/sign-in-with-username-and-password/$sveltekit.md b/documentation/content/guidebook/sign-in-with-username-and-password/$sveltekit.md index a29ad44ca..b27a7a0f5 100644 --- a/documentation/content/guidebook/sign-in-with-username-and-password/$sveltekit.md +++ b/documentation/content/guidebook/sign-in-with-username-and-password/$sveltekit.md @@ -13,13 +13,13 @@ This guide will cover how to implement a simple username and password authentica ### Clone project -You can get started immediately by cloning the [SvelteKit example](https://github.com/lucia-auth/lucia/tree/main/examples/sveltekit/username-and-password) from the repository. +You can get started immediately by cloning the [SvelteKit example](https://github.com/lucia-auth/examples/tree/main/sveltekit/username-and-password) from the repository. ``` -npx degit lucia-auth/lucia/examples/sveltekit/username-and-password +npx degit lucia-auth/examples/sveltekit/username-and-password ``` -Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/lucia/tree/main/examples/sveltekit/username-and-password). +Alternatively, you can [open it in StackBlitz](https://stackblitz.com/github/lucia-auth/examples/tree/main/sveltekit/username-and-password). ## Update your database diff --git a/documentation/content/main/contributing.md b/documentation/content/main/contributing.md index ada787ab6..c1227a08b 100644 --- a/documentation/content/main/contributing.md +++ b/documentation/content/main/contributing.md @@ -16,11 +16,9 @@ This repository requires Node.js version 20 and the latest version of [pnpm](htt After forking the project, set up your local fork by running the following command in the root: ``` -pnpm ready +pnpm i ``` -You may need to reset your IDE afterwards. - ## Documentation Writing the documentation is the most time consuming part of maintaining Lucia, so this is one of the best way to contribute! The documentation website is built with [Astro](https://astro.build). @@ -35,7 +33,7 @@ Please open a feature request for anything related to the website's functionalit ### Examples -This is also another great way to contribute to the library. The example should follow existing ones as close as possible. +This is also another great way to contribute to the library. The example should follow existing ones as close as possible. You can find them at [`lucia-auth/examples`](https://github.com/lucia-auth/examples). ## Source code diff --git a/documentation/src/layouts/BaseLayout.astro b/documentation/src/layouts/BaseLayout.astro index f5d691ca6..a5ce6ed8b 100644 --- a/documentation/src/layouts/BaseLayout.astro +++ b/documentation/src/layouts/BaseLayout.astro @@ -6,9 +6,14 @@ type Props = { const { title, description } = Astro.props; -const origin = import.meta.env.DEV - ? Astro.url.origin - : import.meta.env.CF_PAGES_URL; +let origin: string; +if (import.meta.env.CF_PAGES_BRANCH === "main") { + origin = "https://lucia-auth.com"; +} else if (import.meta.env.DEV) { + origin = Astro.url.origin; +} else { + origin = import.meta.env.CF_PAGES_URL; +} const pathname = Astro.url.pathname; diff --git a/examples/astro/email-and-password/.gitignore b/examples/astro/email-and-password/.gitignore deleted file mode 100644 index 8261a4cb1..000000000 --- a/examples/astro/email-and-password/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# build output -dist/ -# generated types -.astro/ - -# dependencies -node_modules/ - -# logs -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* - - -# environment variables -.env -.env.production - -# macOS-specific files -.DS_Store - -main.db \ No newline at end of file diff --git a/examples/astro/email-and-password/.prettierignore b/examples/astro/email-and-password/.prettierignore deleted file mode 100644 index 8295e33aa..000000000 --- a/examples/astro/email-and-password/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -# build output -dist/ \ No newline at end of file diff --git a/examples/astro/email-and-password/README.md b/examples/astro/email-and-password/README.md deleted file mode 100644 index f0e213fea..000000000 --- a/examples/astro/email-and-password/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Email & password example with Lucia and Astro - -This example uses SQLite3 with `better-sqlite3`. - -```bash -# install dependencies -pnpm i - -# run dev server -pnpm dev -``` - -## User schema - -| id | type | unique | -| ---------------- | ----------------------- | :----: | -| `id` | `string` | | -| `email` | `string` | ✓ | -| `email_verified` | `number` (as `boolean`) | ✓ | diff --git a/examples/astro/email-and-password/astro.config.mjs b/examples/astro/email-and-password/astro.config.mjs deleted file mode 100644 index 445ff9c67..000000000 --- a/examples/astro/email-and-password/astro.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from "astro/config"; - -import node from "@astrojs/node"; - -// https://astro.build/config -export default defineConfig({ - output: "server", - adapter: node({ - mode: "standalone" - }) -}); diff --git a/examples/astro/email-and-password/package.json b/examples/astro/email-and-password/package.json deleted file mode 100644 index 5ecbadc93..000000000 --- a/examples/astro/email-and-password/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "email-and-password", - "description": "Email & password example with Lucia and Astro", - "type": "module", - "version": "0.0.1", - "scripts": { - "dev": "astro dev", - "start": "astro dev", - "build": "astro build", - "preview": "astro preview", - "astro": "astro" - }, - "dependencies": { - "@astrojs/node": "^5.3.0", - "@lucia-auth/adapter-sqlite": "latest", - "astro": "^3.0.0", - "better-sqlite3": "^8.4.0", - "kysely": "^0.25.0", - "lucia": "latest" - }, - "devDependencies": { - "@types/better-sqlite3": "^7.6.3" - } -} diff --git a/examples/astro/email-and-password/public/favicon.svg b/examples/astro/email-and-password/public/favicon.svg deleted file mode 100644 index f157bd1c5..000000000 --- a/examples/astro/email-and-password/public/favicon.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/examples/astro/email-and-password/schema.sql b/examples/astro/email-and-password/schema.sql deleted file mode 100644 index 9df84fdaa..000000000 --- a/examples/astro/email-and-password/schema.sql +++ /dev/null @@ -1,28 +0,0 @@ -CREATE TABLE user ( - id VARCHAR(15) PRIMARY KEY, - email VARCHAR(31) NOT NULL UNIQUE, - email_verified INTEGER NOT NULL -); -CREATE TABLE user_key ( - id VARCHAR(255) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - hashed_password VARCHAR(255), - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE user_session ( - id VARCHAR(127) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - active_expires BIGINT NOT NULL, - idle_expires BIGINT NOT NULL, - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE email_verification_token ( - id VARCHAR(63) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - expires BIGINT NOT NULL -); -CREATE TABLE password_reset_token ( - id VARCHAR(63) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - expires BIGINT NOT NULL -); \ No newline at end of file diff --git a/examples/astro/email-and-password/src/app.css b/examples/astro/email-and-password/src/app.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/astro/email-and-password/src/app.css +++ /dev/null @@ -1,10 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.error { - color: red; -} diff --git a/examples/astro/email-and-password/src/env.d.ts b/examples/astro/email-and-password/src/env.d.ts deleted file mode 100644 index 96d5e1a5b..000000000 --- a/examples/astro/email-and-password/src/env.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -/// -declare namespace App { - interface Locals { - auth: import("lucia").AuthRequest; - } -} - -/// -declare namespace Lucia { - type Auth = import("./lib/lucia").Auth; - type DatabaseUserAttributes = { - email: string; - email_verified: number; - }; - type DatabaseSessionAttributes = {}; -} diff --git a/examples/astro/email-and-password/src/lib/db.ts b/examples/astro/email-and-password/src/lib/db.ts deleted file mode 100644 index 2cc4dfbf6..000000000 --- a/examples/astro/email-and-password/src/lib/db.ts +++ /dev/null @@ -1,49 +0,0 @@ -import sqlite from "better-sqlite3"; -import fs from "fs"; -import { Kysely, SqliteDialect } from "kysely"; - -import type { ColumnType } from "kysely"; - -export const sqliteDatabase = sqlite(":memory:"); -sqliteDatabase.exec(fs.readFileSync("schema.sql", "utf8")); - -const dialect = new SqliteDialect({ - database: sqliteDatabase -}); - -export const db = new Kysely({ - dialect -}); - -type Database = { - user: UserTable; - user_session: SessionTable; - user_key: KeyTable; - email_verification_token: VerificationTokenTable; - password_reset_token: VerificationTokenTable; -}; - -type UserTable = { - id: string; - email: string; - email_verified: number; -}; - -type SessionTable = { - id: string; - user_id: string; - idle_expires: ColumnType; - active_expires: ColumnType; -}; - -type KeyTable = { - id: string; - user_id: string; - hashed_password: null | string; -}; - -type VerificationTokenTable = { - id: string; - user_id: string; - expires: ColumnType; -}; diff --git a/examples/astro/email-and-password/src/lib/email.ts b/examples/astro/email-and-password/src/lib/email.ts deleted file mode 100644 index b6613f73e..000000000 --- a/examples/astro/email-and-password/src/lib/email.ts +++ /dev/null @@ -1,16 +0,0 @@ -export const sendEmailVerificationLink = async (token: string) => { - const url = `http://localhost:3000/email-verification/${token}`; - console.log(`Your email verification link: ${url}`); -}; - -export const sendPasswordResetLink = async (token: string) => { - const url = `http://localhost:3000/password-reset/${token}`; - console.log(`Your password reset link: ${url}`); -}; - -export const isValidEmail = (maybeEmail: unknown): maybeEmail is string => { - if (typeof maybeEmail !== "string") return false; - if (maybeEmail.length > 255) return false; - const emailRegexp = /^.+@.+$/; // [one or more character]@[one or more character] - return emailRegexp.test(maybeEmail); -}; diff --git a/examples/astro/email-and-password/src/lib/lucia.ts b/examples/astro/email-and-password/src/lib/lucia.ts deleted file mode 100644 index a086e863b..000000000 --- a/examples/astro/email-and-password/src/lib/lucia.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { lucia } from "lucia"; -import { betterSqlite3 } from "@lucia-auth/adapter-sqlite"; -import { astro } from "lucia/middleware"; -import { sqliteDatabase } from "./db"; - -export const auth = lucia({ - adapter: betterSqlite3(sqliteDatabase, { - user: "user", - session: "user_session", - key: "user_key" - }), - middleware: astro(), - env: import.meta.env.DEV ? "DEV" : "PROD", - getUserAttributes: (data) => { - return { - email: data.email, - emailVerified: Boolean(data.email_verified) - }; - } -}); - -export type Auth = typeof auth; diff --git a/examples/astro/email-and-password/src/lib/token.ts b/examples/astro/email-and-password/src/lib/token.ts deleted file mode 100644 index 4f194f394..000000000 --- a/examples/astro/email-and-password/src/lib/token.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { db } from "./db"; -import { generateRandomString, isWithinExpiration } from "lucia/utils"; - -const EXPIRES_IN = 1000 * 60 * 60 * 2; // 2 hours - -export const generateEmailVerificationToken = async (userId: string) => { - const storedUserTokens = await db - .selectFrom("email_verification_token") - .selectAll() - .where("user_id", "=", userId) - .execute(); - if (storedUserTokens.length > 0) { - const reusableStoredToken = storedUserTokens.find((token) => { - // check if expiration is within 1 hour - // and reuse the token if true - return isWithinExpiration(Number(token.expires) - EXPIRES_IN / 2); - }); - if (reusableStoredToken) return reusableStoredToken.id; - } - const token = generateRandomString(63); - await db - .insertInto("email_verification_token") - .values({ - id: token, - expires: new Date().getTime() + EXPIRES_IN, - user_id: userId - }) - .executeTakeFirst(); - return token; -}; - -export const validateEmailVerificationToken = async (token: string) => { - const storedToken = await db.transaction().execute(async (trx) => { - const storedToken = await trx - .selectFrom("email_verification_token") - .selectAll() - .where("id", "=", token) - .executeTakeFirst(); - if (!storedToken) throw new Error("Invalid token"); - await trx - .deleteFrom("email_verification_token") - .where("user_id", "=", storedToken.user_id) - .executeTakeFirst(); - return storedToken; - }); - const tokenExpires = Number(storedToken.expires); // bigint => number conversion - if (!isWithinExpiration(tokenExpires)) { - throw new Error("Expired token"); - } - return storedToken.user_id; -}; - -export const generatePasswordResetToken = async (userId: string) => { - const storedUserTokens = await db - .selectFrom("password_reset_token") - .selectAll() - .where("user_id", "=", userId) - .execute(); - if (storedUserTokens.length > 0) { - const reusableStoredToken = storedUserTokens.find((token) => { - // check if expiration is within 1 hour - // and reuse the token if true - return isWithinExpiration(Number(token.expires) - EXPIRES_IN / 2); - }); - if (reusableStoredToken) return reusableStoredToken.id; - } - const token = generateRandomString(63); - await db - .insertInto("password_reset_token") - .values({ - id: token, - expires: new Date().getTime() + EXPIRES_IN, - user_id: userId - }) - .executeTakeFirst(); - return token; -}; - -export const validatePasswordResetToken = async (token: string) => { - const storedToken = await db.transaction().execute(async (trx) => { - const storedToken = await trx - .selectFrom("password_reset_token") - .selectAll() - .where("id", "=", token) - .executeTakeFirst(); - if (!storedToken) throw new Error("Invalid token"); - await trx - .deleteFrom("password_reset_token") - .where("id", "=", token) - .executeTakeFirst(); - return storedToken; - }); - const tokenExpires = Number(storedToken.expires); // bigint => number conversion - if (!isWithinExpiration(tokenExpires)) { - throw new Error("Expired token"); - } - return storedToken.user_id; -}; - -export const isValidPasswordResetToken = async (token: string) => { - const storedToken = await db - .selectFrom("password_reset_token") - .selectAll() - .where("id", "=", token) - .executeTakeFirst(); - if (!storedToken) return false; - const tokenExpires = Number(storedToken.expires); // bigint => number conversion - if (!isWithinExpiration(tokenExpires)) { - return false; - } - return true; -}; diff --git a/examples/astro/email-and-password/src/middleware.ts b/examples/astro/email-and-password/src/middleware.ts deleted file mode 100644 index 3d7868acc..000000000 --- a/examples/astro/email-and-password/src/middleware.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { auth } from "./lib/lucia"; - -import type { MiddlewareResponseHandler } from "astro"; - -export const onRequest: MiddlewareResponseHandler = async (context, next) => { - context.locals.auth = auth.handleRequest(context); - return await next(); -}; diff --git a/examples/astro/email-and-password/src/pages/email-verification/[token].ts b/examples/astro/email-and-password/src/pages/email-verification/[token].ts deleted file mode 100644 index 661638e79..000000000 --- a/examples/astro/email-and-password/src/pages/email-verification/[token].ts +++ /dev/null @@ -1,36 +0,0 @@ -import { auth } from "../../lib/lucia"; -import { validateEmailVerificationToken } from "../../lib/token"; - -import type { APIRoute } from "astro"; - -export const get: APIRoute = async ({ params, locals }) => { - const { token } = params; - if (!token) { - return new Response(null, { - status: 400 - }); - } - try { - const userId = await validateEmailVerificationToken(token); - const user = await auth.getUser(userId); - await auth.invalidateAllUserSessions(user.userId); - await auth.updateUserAttributes(user.userId, { - email_verified: Number(true) - }); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - locals.auth.setSession(session); - return new Response(null, { - status: 302, - headers: { - Location: "/" - } - }); - } catch { - return new Response("Invalid email verification link", { - status: 400 - }); - } -}; diff --git a/examples/astro/email-and-password/src/pages/email-verification/index.astro b/examples/astro/email-and-password/src/pages/email-verification/index.astro deleted file mode 100644 index cdb917baf..000000000 --- a/examples/astro/email-and-password/src/pages/email-verification/index.astro +++ /dev/null @@ -1,45 +0,0 @@ ---- -import "../../app.css"; - -import { sendEmailVerificationLink } from "../../lib/email"; -import { generateEmailVerificationToken } from "../../lib/token"; - -let success = false; -let errorMessage: string | null = null; - -const session = await Astro.locals.auth.validate(); -if (!session) return Astro.redirect("/login"); -if (session.user.emailVerified) { - return Astro.redirect("/"); -} -if (Astro.request.method === "POST") { - try { - const token = await generateEmailVerificationToken(session.user.userId); - await sendEmailVerificationLink(token); - success = true; - } catch { - errorMessage = "An unknown error occurred"; - Astro.response.status = 500; - } -} ---- - - - - - - - - Email & password auth with Lucia - - -

Email verification

-

Your email verification link was sent to your inbox (i.e. console).

-

Resend verification link

-
- -
- {success &&

Your verification link was resent

} -

{errorMessage}

- - diff --git a/examples/astro/email-and-password/src/pages/index.astro b/examples/astro/email-and-password/src/pages/index.astro deleted file mode 100644 index 4ea7c55bc..000000000 --- a/examples/astro/email-and-password/src/pages/index.astro +++ /dev/null @@ -1,27 +0,0 @@ ---- -import "../app.css"; - -const session = await Astro.locals.auth.validate(); -if (!session) return Astro.redirect("/login"); -if (!session.user.emailVerified) { - return Astro.redirect("/email-verification"); -} ---- - - - - - - - - Email & password auth with Lucia - - -

Profile

-

User id: {session.user.userId}

-

Email: {session.user.email}

-
- -
- - diff --git a/examples/astro/email-and-password/src/pages/login.astro b/examples/astro/email-and-password/src/pages/login.astro deleted file mode 100644 index 111f141f5..000000000 --- a/examples/astro/email-and-password/src/pages/login.astro +++ /dev/null @@ -1,86 +0,0 @@ ---- -import "../app.css"; -import { isValidEmail } from "../lib/email"; - -import { auth } from "../lib/lucia"; -import { LuciaError } from "lucia"; - -let errorMessage: string | null = null; -let emailInput = ""; - -// check for form submissions -if (Astro.request.method === "POST") { - const formData = await Astro.request.formData(); - const email = formData.get("email"); - const password = formData.get("password"); - // basic check - if (typeof email === "string") { - emailInput = email; - } - const validPassword = - typeof password === "string" && - password.length >= 1 && - password.length <= 255; - if (isValidEmail(email) && validPassword) { - try { - // find user by key - // and validate password - const key = await auth.useKey("email", email.toLowerCase(), password); - const session = await auth.createSession({ - userId: key.userId, - attributes: {} - }); - Astro.locals.auth.setSession(session); // set session cookie - return Astro.redirect("/", 302); // redirect to profile page - } catch (e) { - if ( - e instanceof LuciaError && - (e.message === "AUTH_INVALID_KEY_ID" || - e.message === "AUTH_INVALID_PASSWORD") - ) { - // user does not exist - // or invalid password - errorMessage = "Incorrect email or password"; - Astro.response.status = 400; - } else { - errorMessage = "An unknown error occurred"; - Astro.response.status = 500; - } - } - } else { - errorMessage = "Invalid input"; - Astro.response.status = 400; - } -} - -const session = await Astro.locals.auth.validate(); -if (session) { - if (!session.user.emailVerified) { - return Astro.redirect("/email-verification"); - } - return Astro.redirect("/"); -} ---- - - - - - - - - Email & password auth with Lucia - - -

Sign in

-
- -
- -
- -
-

{errorMessage}

- Reset password - Create an account - - diff --git a/examples/astro/email-and-password/src/pages/logout.ts b/examples/astro/email-and-password/src/pages/logout.ts deleted file mode 100644 index e65c1d740..000000000 --- a/examples/astro/email-and-password/src/pages/logout.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { auth } from "../lib/lucia"; - -import type { APIRoute } from "astro"; - -export const post: APIRoute = async (context) => { - const session = await context.locals.auth.validate(); - if (!session) { - return new Response("Unauthorized", { - status: 401 - }); - } - // make sure to invalidate the current session! - await auth.invalidateSession(session.sessionId); - // delete session cookie - context.locals.auth.setSession(null); - return context.redirect("/login", 302); -}; diff --git a/examples/astro/email-and-password/src/pages/password-reset/[token].astro b/examples/astro/email-and-password/src/pages/password-reset/[token].astro deleted file mode 100644 index 136b03678..000000000 --- a/examples/astro/email-and-password/src/pages/password-reset/[token].astro +++ /dev/null @@ -1,67 +0,0 @@ ---- -import "../../app.css"; - -import { auth } from "../../lib/lucia"; -import { validatePasswordResetToken } from "../../lib/token"; - -let errorMessage = ""; -if (Astro.request.method === "POST") { - const formData = await Astro.request.formData(); - const password = formData.get("password"); - // basic check - const validPassword = - typeof password === "string" && - password.length >= 6 && - password.length <= 255; - if (validPassword) { - try { - const { token } = Astro.params; - if (!token) { - return new Response(null, { - status: 404 - }); - } - const userId = await validatePasswordResetToken(token); - let user = await auth.getUser(userId); - await auth.invalidateAllUserSessions(user.userId); - await auth.updateKeyPassword("email", user.email, password); - if (!user.emailVerified) { - user = await auth.updateUserAttributes(user.userId, { - email_verified: Number(true) - }); - } - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - Astro.locals.auth.setSession(session); - return Astro.redirect("/"); - } catch (e) { - errorMessage = "Invalid or expired password reset link"; - Astro.response.status = 400; - } - } else { - errorMessage = "Invalid password"; - Astro.response.status = 400; - } -} ---- - - - - - - - - Email & password auth with Lucia - - -

Reset password

-
- -
- -
-

{errorMessage}

- - diff --git a/examples/astro/email-and-password/src/pages/password-reset/index.astro b/examples/astro/email-and-password/src/pages/password-reset/index.astro deleted file mode 100644 index bb058c64a..000000000 --- a/examples/astro/email-and-password/src/pages/password-reset/index.astro +++ /dev/null @@ -1,65 +0,0 @@ ---- -import "../../app.css"; - -import { db } from "../../lib/db"; -import { sendPasswordResetLink, isValidEmail } from "../../lib/email"; -import { auth } from "../../lib/lucia"; -import { generatePasswordResetToken } from "../../lib/token"; - -let emailInput = ""; -let success = false; -let errorMessage: string | null = null; - -if (Astro.request.method === "POST") { - const formData = await Astro.request.formData(); - const email = formData.get("email"); - if (typeof email === "string") { - emailInput = email; - } - if (isValidEmail(email)) { - try { - const storedUser = await db - .selectFrom("user") - .selectAll() - .where("email", "=", email) - .executeTakeFirst(); - if (storedUser) { - const user = auth.transformDatabaseUser(storedUser); - const token = await generatePasswordResetToken(user.userId); - await sendPasswordResetLink(token); - success = true; - } else { - errorMessage = "User does not exist"; - Astro.response.status = 400; - } - } catch (e) { - errorMessage = "An unknown error occurred"; - Astro.response.status = 500; - } - } else { - errorMessage = "Invalid email"; - Astro.response.status = 400; - } -} ---- - - - - - - - - Email & password auth with Lucia - - -

Reset password

-
- -
- -
-

{errorMessage}

- {success &&

Your password reset link was sent to your inbox

} - Sign in - - diff --git a/examples/astro/email-and-password/src/pages/signup.astro b/examples/astro/email-and-password/src/pages/signup.astro deleted file mode 100644 index a70dc3023..000000000 --- a/examples/astro/email-and-password/src/pages/signup.astro +++ /dev/null @@ -1,92 +0,0 @@ ---- -import "../app.css"; -import { isValidEmail, sendEmailVerificationLink } from "../lib/email"; - -import { auth } from "../lib/lucia"; -import { SqliteError } from "better-sqlite3"; -import { generateEmailVerificationToken } from "../lib/token"; - -let emailInput = ""; -let errorMessage = ""; - -// check for form submissions -if (Astro.request.method === "POST") { - const formData = await Astro.request.formData(); - const email = formData.get("email"); - const password = formData.get("password"); - if (typeof email === "string") { - emailInput = email; - } - // basic check - const validPassword = - typeof password === "string" && - password.length >= 6 && - password.length <= 255; - if (isValidEmail(email) && validPassword) { - try { - const user = await auth.createUser({ - key: { - providerId: "email", // auth method - providerUserId: email.toLowerCase(), // unique id when using "email" auth method - password // hashed by Lucia - }, - attributes: { - email, - email_verified: Number(false) - } - }); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - Astro.locals.auth.setSession(session); // set session cookie - const token = await generateEmailVerificationToken(user.userId); - await sendEmailVerificationLink(token); - return Astro.redirect("/email-verification", 302); - } catch (e) { - // this part depends on the database you're using - // check for unique constraint error in user table - if (e instanceof SqliteError && e.code === "SQLITE_CONSTRAINT_UNIQUE") { - errorMessage = "Account already exists"; - Astro.response.status = 400; - } else { - errorMessage = "An unknown error occurred"; - Astro.response.status = 500; - } - } - } else { - errorMessage = "Invalid input"; - Astro.response.status = 400; - } -} - -const session = await Astro.locals.auth.validate(); -if (session) { - if (!session.user.emailVerified) { - return Astro.redirect("/email-verification"); - } - return Astro.redirect("/"); -} ---- - - - - - - - - Email & password auth with Lucia - - -

Sign up

-
- -
- -
- -
-

{errorMessage}

- Sign in - - diff --git a/examples/astro/email-and-password/tsconfig.json b/examples/astro/email-and-password/tsconfig.json deleted file mode 100644 index a3f698102..000000000 --- a/examples/astro/email-and-password/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "astro/tsconfigs/strict" -} diff --git a/examples/astro/github-oauth/.env.example b/examples/astro/github-oauth/.env.example deleted file mode 100644 index 0e0e5f95b..000000000 --- a/examples/astro/github-oauth/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -GITHUB_CLIENT_ID="" -GITHUB_CLIENT_SECRET="" \ No newline at end of file diff --git a/examples/astro/github-oauth/.gitignore b/examples/astro/github-oauth/.gitignore deleted file mode 100644 index 8261a4cb1..000000000 --- a/examples/astro/github-oauth/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# build output -dist/ -# generated types -.astro/ - -# dependencies -node_modules/ - -# logs -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* - - -# environment variables -.env -.env.production - -# macOS-specific files -.DS_Store - -main.db \ No newline at end of file diff --git a/examples/astro/github-oauth/.prettierignore b/examples/astro/github-oauth/.prettierignore deleted file mode 100644 index 8295e33aa..000000000 --- a/examples/astro/github-oauth/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -# build output -dist/ \ No newline at end of file diff --git a/examples/astro/github-oauth/README.md b/examples/astro/github-oauth/README.md deleted file mode 100644 index 7dbd6b98a..000000000 --- a/examples/astro/github-oauth/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# GitHub OAuth example with Lucia and Astro - -This example uses SQLite3 with `better-sqlite3`. Make sure to setup your `.env` file. - -```bash -# install dependencies -pnpm i - -# run dev server -pnpm dev -``` - -## Setup GitHub OAuth - -[Create a new GitHub OAuth app](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app). The redirect uri should be set to `localhost:5173/login/github/callback`. Copy and paste the client id and secret into `.env`. - -```bash -GITHUB_CLIENT_ID="" -GITHUB_CLIENT_SECRET="" -``` - -## User schema - -| id | type | unique | -| ---------- | -------- | :----: | -| `id` | `string` | | -| `username` | `string` | | diff --git a/examples/astro/github-oauth/astro.config.mjs b/examples/astro/github-oauth/astro.config.mjs deleted file mode 100644 index 445ff9c67..000000000 --- a/examples/astro/github-oauth/astro.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from "astro/config"; - -import node from "@astrojs/node"; - -// https://astro.build/config -export default defineConfig({ - output: "server", - adapter: node({ - mode: "standalone" - }) -}); diff --git a/examples/astro/github-oauth/package.json b/examples/astro/github-oauth/package.json deleted file mode 100644 index cb74156a4..000000000 --- a/examples/astro/github-oauth/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "github-oauth", - "description": "GitHub OAuth example with Lucia and Astro", - "type": "module", - "version": "0.0.1", - "scripts": { - "dev": "astro dev", - "start": "astro dev", - "build": "astro build", - "preview": "astro preview", - "astro": "astro" - }, - "dependencies": { - "@astrojs/node": "^5.3.0", - "@lucia-auth/adapter-sqlite": "latest", - "@lucia-auth/oauth": "latest", - "astro": "^3.0.0", - "better-sqlite3": "^8.4.0", - "lucia": "latest" - }, - "devDependencies": { - "@types/better-sqlite3": "^7.6.3" - } -} diff --git a/examples/astro/github-oauth/public/favicon.svg b/examples/astro/github-oauth/public/favicon.svg deleted file mode 100644 index f157bd1c5..000000000 --- a/examples/astro/github-oauth/public/favicon.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/examples/astro/github-oauth/schema.sql b/examples/astro/github-oauth/schema.sql deleted file mode 100644 index 013ddfbc3..000000000 --- a/examples/astro/github-oauth/schema.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE user ( - id VARCHAR(15) PRIMARY KEY, - username VARCHAR(31) NOT NULL -); -CREATE TABLE user_key ( - id VARCHAR(255) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - hashed_password VARCHAR(255), - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE user_session ( - id VARCHAR(127) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - active_expires BIGINT NOT NULL, - idle_expires BIGINT NOT NULL, - FOREIGN KEY (user_id) REFERENCES user(id) -); \ No newline at end of file diff --git a/examples/astro/github-oauth/src/app.css b/examples/astro/github-oauth/src/app.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/astro/github-oauth/src/app.css +++ /dev/null @@ -1,10 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.error { - color: red; -} diff --git a/examples/astro/github-oauth/src/env.d.ts b/examples/astro/github-oauth/src/env.d.ts deleted file mode 100644 index aefa7d97c..000000000 --- a/examples/astro/github-oauth/src/env.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -/// -declare namespace App { - interface Locals { - auth: import("lucia").AuthRequest; - } -} - -/// -declare namespace Lucia { - type Auth = import("./lib/lucia").Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = {}; -} diff --git a/examples/astro/github-oauth/src/lib/lucia.ts b/examples/astro/github-oauth/src/lib/lucia.ts deleted file mode 100644 index e4b289347..000000000 --- a/examples/astro/github-oauth/src/lib/lucia.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { lucia } from "lucia"; -import { betterSqlite3 } from "@lucia-auth/adapter-sqlite"; -import { github } from "@lucia-auth/oauth/providers"; -import { astro } from "lucia/middleware"; - -import sqlite from "better-sqlite3"; -import fs from "fs"; - -const db = sqlite(":memory:"); -db.exec(fs.readFileSync("schema.sql", "utf8")); - -export const auth = lucia({ - adapter: betterSqlite3(db, { - user: "user", - session: "user_session", - key: "user_key" - }), - middleware: astro(), - env: import.meta.env.DEV ? "DEV" : "PROD", - getUserAttributes: (data) => { - return { - githubUsername: data.username - }; - } -}); - -export const githubAuth = github(auth, { - clientId: import.meta.env.GITHUB_CLIENT_ID, - clientSecret: import.meta.env.GITHUB_CLIENT_SECRET -}); - -export type Auth = typeof auth; diff --git a/examples/astro/github-oauth/src/middleware.ts b/examples/astro/github-oauth/src/middleware.ts deleted file mode 100644 index 3d7868acc..000000000 --- a/examples/astro/github-oauth/src/middleware.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { auth } from "./lib/lucia"; - -import type { MiddlewareResponseHandler } from "astro"; - -export const onRequest: MiddlewareResponseHandler = async (context, next) => { - context.locals.auth = auth.handleRequest(context); - return await next(); -}; diff --git a/examples/astro/github-oauth/src/pages/index.astro b/examples/astro/github-oauth/src/pages/index.astro deleted file mode 100644 index ac0cf26ab..000000000 --- a/examples/astro/github-oauth/src/pages/index.astro +++ /dev/null @@ -1,24 +0,0 @@ ---- -import "../app.css"; - -const session = await Astro.locals.auth.validate(); -if (!session) return Astro.redirect("/login", 302); ---- - - - - - - - - GitHub OAuth with Lucia - - -

Profile

-

User id: {session.user.userId}

-

GitHub username: {session.user.githubUsername}

-
- -
- - diff --git a/examples/astro/github-oauth/src/pages/login/github/callback.ts b/examples/astro/github-oauth/src/pages/login/github/callback.ts deleted file mode 100644 index c5633ba2c..000000000 --- a/examples/astro/github-oauth/src/pages/login/github/callback.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { auth, githubAuth } from "../../../lib/lucia.js"; -import { OAuthRequestError } from "@lucia-auth/oauth"; - -import type { APIRoute } from "astro"; - -export const get: APIRoute = async (context) => { - const session = await context.locals.auth.validate(); - if (session) { - return context.redirect("/", 302); // redirect to profile page - } - const storedState = context.cookies.get("github_oauth_state")?.value; - const state = context.url.searchParams.get("state"); - const code = context.url.searchParams.get("code"); - // validate state - if (!storedState || !state || storedState !== state || !code) { - return new Response(null, { - status: 400 - }); - } - try { - const { getExistingUser, githubUser, createUser } = - await githubAuth.validateCallback(code); - - const getUser = async () => { - const existingUser = await getExistingUser(); - if (existingUser) return existingUser; - const user = await createUser({ - attributes: { - username: githubUser.login - } - }); - return user; - }; - - const user = await getUser(); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - context.locals.auth.setSession(session); - return context.redirect("/", 302); // redirect to profile page - } catch (e) { - if (e instanceof OAuthRequestError) { - // invalid code - return new Response(null, { - status: 400 - }); - } - return new Response(null, { - status: 500 - }); - } -}; diff --git a/examples/astro/github-oauth/src/pages/login/github/index.ts b/examples/astro/github-oauth/src/pages/login/github/index.ts deleted file mode 100644 index c148ed395..000000000 --- a/examples/astro/github-oauth/src/pages/login/github/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { githubAuth } from "../../../lib/lucia"; - -import type { APIRoute } from "astro"; - -export const get: APIRoute = async (context) => { - const session = await context.locals.auth.validate(); - if (session) { - return context.redirect("/", 302); // redirect to profile page - } - const [url, state] = await githubAuth.getAuthorizationUrl(); - context.cookies.set("github_oauth_state", state, { - httpOnly: true, - secure: !import.meta.env.DEV, - path: "/", - maxAge: 60 * 60 - }); - return context.redirect(url.toString(), 302); -}; diff --git a/examples/astro/github-oauth/src/pages/login/index.astro b/examples/astro/github-oauth/src/pages/login/index.astro deleted file mode 100644 index c4682f441..000000000 --- a/examples/astro/github-oauth/src/pages/login/index.astro +++ /dev/null @@ -1,20 +0,0 @@ ---- -import "../../app.css"; - -const session = await Astro.locals.auth.validate(); -if (session) return Astro.redirect("/", 302); // redirect to profile page ---- - - - - - - - - GitHub OAuth with Lucia - - -

Sign in

- Sign in with GitHub - - diff --git a/examples/astro/github-oauth/src/pages/logout.ts b/examples/astro/github-oauth/src/pages/logout.ts deleted file mode 100644 index e65c1d740..000000000 --- a/examples/astro/github-oauth/src/pages/logout.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { auth } from "../lib/lucia"; - -import type { APIRoute } from "astro"; - -export const post: APIRoute = async (context) => { - const session = await context.locals.auth.validate(); - if (!session) { - return new Response("Unauthorized", { - status: 401 - }); - } - // make sure to invalidate the current session! - await auth.invalidateSession(session.sessionId); - // delete session cookie - context.locals.auth.setSession(null); - return context.redirect("/login", 302); -}; diff --git a/examples/astro/github-oauth/tsconfig.json b/examples/astro/github-oauth/tsconfig.json deleted file mode 100644 index a3f698102..000000000 --- a/examples/astro/github-oauth/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "astro/tsconfigs/strict" -} diff --git a/examples/astro/username-and-password/.gitignore b/examples/astro/username-and-password/.gitignore deleted file mode 100644 index 8261a4cb1..000000000 --- a/examples/astro/username-and-password/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# build output -dist/ -# generated types -.astro/ - -# dependencies -node_modules/ - -# logs -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* - - -# environment variables -.env -.env.production - -# macOS-specific files -.DS_Store - -main.db \ No newline at end of file diff --git a/examples/astro/username-and-password/.prettierignore b/examples/astro/username-and-password/.prettierignore deleted file mode 100644 index 8295e33aa..000000000 --- a/examples/astro/username-and-password/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -# build output -dist/ \ No newline at end of file diff --git a/examples/astro/username-and-password/README.md b/examples/astro/username-and-password/README.md deleted file mode 100644 index 61d28b4dd..000000000 --- a/examples/astro/username-and-password/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Username & password example with Lucia and Astro - -This example uses SQLite3 with `better-sqlite3`. - -```bash -# install dependencies -pnpm i - -# run dev server -pnpm dev -``` - -## User schema - -| id | type | unique | -| ---------- | -------- | :----: | -| `id` | `string` | | -| `username` | `string` | ✓ | diff --git a/examples/astro/username-and-password/astro.config.mjs b/examples/astro/username-and-password/astro.config.mjs deleted file mode 100644 index 445ff9c67..000000000 --- a/examples/astro/username-and-password/astro.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from "astro/config"; - -import node from "@astrojs/node"; - -// https://astro.build/config -export default defineConfig({ - output: "server", - adapter: node({ - mode: "standalone" - }) -}); diff --git a/examples/astro/username-and-password/package.json b/examples/astro/username-and-password/package.json deleted file mode 100644 index bd1594ae5..000000000 --- a/examples/astro/username-and-password/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "username-and-password", - "description": "Username & password example with Lucia and Astro", - "type": "module", - "version": "0.0.1", - "scripts": { - "dev": "astro dev", - "start": "astro dev", - "build": "astro build", - "preview": "astro preview", - "astro": "astro" - }, - "dependencies": { - "@astrojs/node": "^5.3.0", - "@lucia-auth/adapter-sqlite": "latest", - "astro": "^3.0.0", - "better-sqlite3": "^8.4.0", - "lucia": "latest" - }, - "devDependencies": { - "@types/better-sqlite3": "^7.6.3" - } -} diff --git a/examples/astro/username-and-password/public/favicon.svg b/examples/astro/username-and-password/public/favicon.svg deleted file mode 100644 index f157bd1c5..000000000 --- a/examples/astro/username-and-password/public/favicon.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/examples/astro/username-and-password/schema.sql b/examples/astro/username-and-password/schema.sql deleted file mode 100644 index c62ad0cfb..000000000 --- a/examples/astro/username-and-password/schema.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE user ( - id VARCHAR(15) PRIMARY KEY, - username VARCHAR(31) NOT NULL UNIQUE -); -CREATE TABLE user_key ( - id VARCHAR(255) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - hashed_password VARCHAR(255), - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE user_session ( - id VARCHAR(127) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - active_expires BIGINT NOT NULL, - idle_expires BIGINT NOT NULL, - FOREIGN KEY (user_id) REFERENCES user(id) -); \ No newline at end of file diff --git a/examples/astro/username-and-password/src/app.css b/examples/astro/username-and-password/src/app.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/astro/username-and-password/src/app.css +++ /dev/null @@ -1,10 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.error { - color: red; -} diff --git a/examples/astro/username-and-password/src/env.d.ts b/examples/astro/username-and-password/src/env.d.ts deleted file mode 100644 index aefa7d97c..000000000 --- a/examples/astro/username-and-password/src/env.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -/// -declare namespace App { - interface Locals { - auth: import("lucia").AuthRequest; - } -} - -/// -declare namespace Lucia { - type Auth = import("./lib/lucia").Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = {}; -} diff --git a/examples/astro/username-and-password/src/lib/lucia.ts b/examples/astro/username-and-password/src/lib/lucia.ts deleted file mode 100644 index 7e2060b0d..000000000 --- a/examples/astro/username-and-password/src/lib/lucia.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { lucia } from "lucia"; -import { betterSqlite3 } from "@lucia-auth/adapter-sqlite"; -import { astro } from "lucia/middleware"; -// import "lucia/polyfill/node"; - -import sqlite from "better-sqlite3"; -import fs from "fs"; - -const db = sqlite(":memory:"); -db.exec(fs.readFileSync("schema.sql", "utf8")); - -export const auth = lucia({ - adapter: betterSqlite3(db, { - user: "user", - session: "user_session", - key: "user_key" - }), - middleware: astro(), - env: import.meta.env.DEV ? "DEV" : "PROD", - getUserAttributes: (data) => { - return { - username: data.username - }; - } -}); - -export type Auth = typeof auth; diff --git a/examples/astro/username-and-password/src/middleware.ts b/examples/astro/username-and-password/src/middleware.ts deleted file mode 100644 index 3d7868acc..000000000 --- a/examples/astro/username-and-password/src/middleware.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { auth } from "./lib/lucia"; - -import type { MiddlewareResponseHandler } from "astro"; - -export const onRequest: MiddlewareResponseHandler = async (context, next) => { - context.locals.auth = auth.handleRequest(context); - return await next(); -}; diff --git a/examples/astro/username-and-password/src/pages/index.astro b/examples/astro/username-and-password/src/pages/index.astro deleted file mode 100644 index 92a0d91ca..000000000 --- a/examples/astro/username-and-password/src/pages/index.astro +++ /dev/null @@ -1,24 +0,0 @@ ---- -import "../app.css"; - -const session = await Astro.locals.auth.validate(); -if (!session) return Astro.redirect("/login", 302); ---- - - - - - - - - Username & password auth with Lucia - - -

Profile

-

User id: {session.user.userId}

-

Username: {session.user.username}

-
- -
- - diff --git a/examples/astro/username-and-password/src/pages/login.astro b/examples/astro/username-and-password/src/pages/login.astro deleted file mode 100644 index 13938b073..000000000 --- a/examples/astro/username-and-password/src/pages/login.astro +++ /dev/null @@ -1,87 +0,0 @@ ---- -import "../app.css"; - -import { auth } from "../lib/lucia"; -import { LuciaError } from "lucia"; - -let errorMessage: string | null = null; -let usernameInput = ""; - -// check for form submissions -if (Astro.request.method === "POST") { - const formData = await Astro.request.formData(); - const username = formData.get("username"); - const password = formData.get("password"); - // basic check - if (typeof username === "string") { - usernameInput = username; - } - const validUsername = - typeof username === "string" && - username.length >= 4 && - username.length <= 31; - const validPassword = - typeof password === "string" && - password.length >= 6 && - password.length <= 255; - if (validUsername && validPassword) { - try { - // find user by key - // and validate password - const key = await auth.useKey( - "username", - username.toLowerCase(), - password - ); - const session = await auth.createSession({ - userId: key.userId, - attributes: {} - }); - Astro.locals.auth.setSession(session); // set session cookie - return Astro.redirect("/", 302); // redirect to profile page - } catch (e) { - if ( - e instanceof LuciaError && - (e.message === "AUTH_INVALID_KEY_ID" || - e.message === "AUTH_INVALID_PASSWORD") - ) { - // user does not exist - // or invalid password - errorMessage = "Incorrect username or password"; - Astro.response.status = 400; - } else { - errorMessage = "An unknown error occurred"; - Astro.response.status = 500; - } - } - } else { - errorMessage = "Invalid input"; - Astro.response.status = 400; - } -} - -const session = await Astro.locals.auth.validate(); -if (session) return Astro.redirect("/", 302); // redirect to profile page ---- - - - - - - - - Username & password auth with Lucia - - -

Sign in

-
- -
- -
- -
-

{errorMessage}

- Create an account - - diff --git a/examples/astro/username-and-password/src/pages/logout.ts b/examples/astro/username-and-password/src/pages/logout.ts deleted file mode 100644 index e65c1d740..000000000 --- a/examples/astro/username-and-password/src/pages/logout.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { auth } from "../lib/lucia"; - -import type { APIRoute } from "astro"; - -export const post: APIRoute = async (context) => { - const session = await context.locals.auth.validate(); - if (!session) { - return new Response("Unauthorized", { - status: 401 - }); - } - // make sure to invalidate the current session! - await auth.invalidateSession(session.sessionId); - // delete session cookie - context.locals.auth.setSession(null); - return context.redirect("/login", 302); -}; diff --git a/examples/astro/username-and-password/src/pages/signup.astro b/examples/astro/username-and-password/src/pages/signup.astro deleted file mode 100644 index e7e32353a..000000000 --- a/examples/astro/username-and-password/src/pages/signup.astro +++ /dev/null @@ -1,86 +0,0 @@ ---- -import "../app.css"; - -import { auth } from "../lib/lucia"; -import { SqliteError } from "better-sqlite3"; - -let usernameInput = ""; -let errorMessage = ""; - -// check for form submissions -if (Astro.request.method === "POST") { - const formData = await Astro.request.formData(); - const username = formData.get("username"); - const password = formData.get("password"); - if (typeof username === "string") { - usernameInput = username; - } - // basic check - const validUsername = - typeof username === "string" && - username.length >= 4 && - username.length <= 31; - const validPassword = - typeof password === "string" && - password.length >= 6 && - password.length <= 255; - if (validUsername && validPassword) { - try { - const user = await auth.createUser({ - key: { - providerId: "username", // auth method - providerUserId: username.toLowerCase(), // unique id when using "username" auth method - password // hashed by Lucia - }, - attributes: { - username - } - }); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - Astro.locals.auth.setSession(session); // set session cookie - return Astro.redirect("/", 302); // redirect to profile page - } catch (e) { - // this part depends on the database you're using - // check for unique constraint error in user table - if (e instanceof SqliteError && e.code === "SQLITE_CONSTRAINT_UNIQUE") { - errorMessage = "Username already taken"; - Astro.response.status = 400; - } else { - errorMessage = "An unknown error occurred"; - Astro.response.status = 500; - } - } - } else { - errorMessage = "Invalid input"; - Astro.response.status = 400; - } -} - -const session = await Astro.locals.auth.validate(); -if (session) return Astro.redirect("/", 302); // redirect to profile page ---- - - - - - - - - Username & password auth with Lucia - - -

Sign up

-
- -
- -
- -
-

{errorMessage}

- Sign in - - diff --git a/examples/astro/username-and-password/tsconfig.json b/examples/astro/username-and-password/tsconfig.json deleted file mode 100644 index a3f698102..000000000 --- a/examples/astro/username-and-password/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "astro/tsconfigs/strict" -} diff --git a/examples/electron/github-oauth/README.md b/examples/electron/github-oauth/README.md deleted file mode 100644 index 8e1f8ec59..000000000 --- a/examples/electron/github-oauth/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# GitHub OAuth example with Lucia and Electron - -This example has 2 parts: the Electron application and the TS server with Lucia. Uses SQLite3 with `better-sqlite3` as the database. - -## App - -Inside `app` directory. **Electron Forge does not support PNPM.** - -```bash -# install dependencies -npm i - -# run dev server -npm run start -``` - -## Server - -Inside `server` directory. Make sure to setup your `.env` file. - -```bash -# install dependencies -pnpm i - -# run server on port 3000 -pnpm start -``` - -## Setup GitHub OAuth - -[Create a new GitHub OAuth app](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app). The redirect uri should be set to `localhost:5173/login/github/callback`. Copy and paste the client id and secret into `.env`. - -```bash -GITHUB_CLIENT_ID="" -GITHUB_CLIENT_SECRET="" -``` - -## User schema - -| id | type | -| ---------- | -------- | -| `id` | `string` | -| `username` | `string` | diff --git a/examples/electron/github-oauth/app/.eslintrc.json b/examples/electron/github-oauth/app/.eslintrc.json deleted file mode 100644 index e1a99dbce..000000000 --- a/examples/electron/github-oauth/app/.eslintrc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:import/recommended", - "plugin:import/electron", - "plugin:import/typescript" - ], - "parser": "@typescript-eslint/parser" -} diff --git a/examples/electron/github-oauth/app/.gitignore b/examples/electron/github-oauth/app/.gitignore deleted file mode 100644 index 8296128de..000000000 --- a/examples/electron/github-oauth/app/.gitignore +++ /dev/null @@ -1,92 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock -.DS_Store - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# Webpack -.webpack/ - -# Vite -.vite/ - -# Electron-Forge -out/ diff --git a/examples/electron/github-oauth/app/forge.config.ts b/examples/electron/github-oauth/app/forge.config.ts deleted file mode 100644 index 9e2065306..000000000 --- a/examples/electron/github-oauth/app/forge.config.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { ForgeConfig } from "@electron-forge/shared-types"; - -import { MakerSquirrel } from "@electron-forge/maker-squirrel"; -import { MakerZIP } from "@electron-forge/maker-zip"; -import { MakerDeb } from "@electron-forge/maker-deb"; -import { MakerRpm } from "@electron-forge/maker-rpm"; -import { VitePlugin } from "@electron-forge/plugin-vite"; - -const config: ForgeConfig = { - packagerConfig: { - protocols: [ - { - name: "Electron Fiddle", - schemes: ["electron-app"] - } - ] - }, - rebuildConfig: {}, - makers: [ - new MakerSquirrel({}), - new MakerZIP({}, ["darwin"]), - new MakerRpm({}), - new MakerDeb({ - options: { - mimeType: ["x-scheme-handler/electron-app"] - } - }) - ], - plugins: [ - new VitePlugin({ - // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc. - // If you are familiar with Vite configuration, it will look really familiar. - build: [ - { - // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`. - entry: "src/main.ts", - config: "vite.main.config.ts" - }, - { - entry: "src/preload.ts", - config: "vite.preload.config.ts" - } - ], - renderer: [ - { - name: "main_window", - config: "vite.renderer.config.ts" - } - ] - }) - ] -}; - -export default config; diff --git a/examples/electron/github-oauth/app/index.html b/examples/electron/github-oauth/app/index.html deleted file mode 100644 index 60f09fa63..000000000 --- a/examples/electron/github-oauth/app/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - Github OAuth with Lucia - - -
-

GitHub OAuth with Lucia

-
-

Profile

-
-
-
- - -
-
- - diff --git a/examples/electron/github-oauth/app/package.json b/examples/electron/github-oauth/app/package.json deleted file mode 100644 index b4261cce6..000000000 --- a/examples/electron/github-oauth/app/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "electron-test", - "productName": "electron-test", - "version": "1.0.0", - "description": "My Electron application description", - "main": ".vite/build/main.js", - "scripts": { - "start": "electron-forge start", - "package": "electron-forge package", - "make": "electron-forge make", - "publish": "electron-forge publish", - "lint": "eslint --ext .ts,.tsx ." - }, - "keywords": [], - "author": { - "name": "pilcrowOnPaper", - "email": "pilcrowonpaper@gmail.com" - }, - "license": "MIT", - "devDependencies": { - "@electron-forge/cli": "^6.4.2", - "@electron-forge/maker-deb": "^6.4.2", - "@electron-forge/maker-rpm": "^6.4.2", - "@electron-forge/maker-squirrel": "^6.4.2", - "@electron-forge/maker-zip": "^6.4.2", - "@electron-forge/plugin-auto-unpack-natives": "^6.4.2", - "@electron-forge/plugin-vite": "^6.4.2", - "@electron-forge/shared-types": "^6.4.2", - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^5.0.0", - "electron": "26.2.1", - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.0", - "ts-node": "^10.0.0", - "typescript": "~4.5.4", - "vite": "^4.4.9" - }, - "dependencies": { - "electron-squirrel-startup": "^1.0.0" - } -} diff --git a/examples/electron/github-oauth/app/src/index.css b/examples/electron/github-oauth/app/src/index.css deleted file mode 100644 index 4afb4dde1..000000000 --- a/examples/electron/github-oauth/app/src/index.css +++ /dev/null @@ -1,7 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} diff --git a/examples/electron/github-oauth/app/src/main.ts b/examples/electron/github-oauth/app/src/main.ts deleted file mode 100644 index 96459f5a9..000000000 --- a/examples/electron/github-oauth/app/src/main.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { app, BrowserWindow, ipcMain, shell, net } from "electron"; -import path from "path"; - -// Handle creating/removing shortcuts on Windows when installing/uninstalling. -if (require("electron-squirrel-startup")) { - app.quit(); -} - -if (process.defaultApp) { - if (process.argv.length >= 2) { - app.setAsDefaultProtocolClient("electron-app", process.execPath, [ - path.resolve(process.argv[1]) - ]); - } -} else { - app.setAsDefaultProtocolClient("electron-app"); -} - -let mainWindow: BrowserWindow; - -const main = () => { - app.on("ready", createWindow); - - // Quit when all windows are closed, except on macOS. There, it's common - // for applications and their menu bar to stay active until the user quits - // explicitly with Cmd + Q. - app.on("window-all-closed", () => { - if (process.platform !== "darwin") { - app.quit(); - } - }); - - app.on("activate", () => { - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } - }); - - app.on("second-instance", (_, commandLine) => { - // Someone tried to run a second instance, we should focus our window. - if (mainWindow) { - if (mainWindow.isMinimized()) mainWindow.restore(); - mainWindow.focus(); - } - const url = commandLine.at(-1); - handleDeepLinkCallback(url); - }); - - app.on("open-url", (_, url) => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } - handleDeepLinkCallback(url); - }); - - ipcMain.handle("auth:signInWithGithub", () => { - shell.openExternal("http://localhost:3000/login/github"); - }); - - ipcMain.handle("auth:getUser", async (e, sessionToken: string) => { - const response = await net.fetch("http://localhost:3000/user", { - headers: { - Authorization: `Bearer ${sessionToken}` - } - }); - if (!response.ok) { - return null; - } - return await response.json(); - }); - - ipcMain.handle("auth:signOut", async (e, sessionToken: string) => { - await net.fetch("http://localhost:3000/logout", { - method: "POST", - headers: { - Authorization: `Bearer ${sessionToken}` - } - }); - }); -}; - -const createWindow = () => { - // Create the browser window. - mainWindow = new BrowserWindow({ - width: 800, - height: 600, - webPreferences: { - preload: path.join(__dirname, "preload.js") - } - }); - - // and load the index.html of the app. - if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { - mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL); - } else { - mainWindow.loadFile( - path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`) - ); - } -}; - -const handleDeepLinkCallback = (url: string) => { - if (!url.startsWith("electron-app://login?")) return; - const params = new URLSearchParams(url.replace("electron-app://login?", "")); - const sessionToken = params.get("session_token"); - if (!sessionToken) return; - mainWindow.webContents.send("auth-state-update", sessionToken); -}; - -if (app.requestSingleInstanceLock()) { - main(); -} else { - app.quit(); -} diff --git a/examples/electron/github-oauth/app/src/preload.ts b/examples/electron/github-oauth/app/src/preload.ts deleted file mode 100644 index b3676b39f..000000000 --- a/examples/electron/github-oauth/app/src/preload.ts +++ /dev/null @@ -1,58 +0,0 @@ -import "./index.css"; - -import { ipcRenderer } from "electron"; - -window.addEventListener("DOMContentLoaded", async () => { - const loginButton = document.getElementById("login-button"); - const profileBody = document.getElementById("profile"); - const logoutButton = document.getElementById("logout-button"); - if (!loginButton || !profileBody || !logoutButton) return; - - const renderUserProfile = (user: User | null) => { - profileBody.textContent = user ? JSON.stringify(user, null, 2) : "(none)"; - }; - - loginButton.addEventListener("click", async () => { - await ipcRenderer.invoke("auth:signInWithGithub"); - }); - - logoutButton.addEventListener("click", async () => { - const sessionToken = localStorage.getItem("session_token"); - if (!sessionToken) return; - await ipcRenderer.invoke("auth:signOut", sessionToken); - renderUserProfile(null); - localStorage.removeItem("session_token"); - }); - - ipcRenderer.on( - "auth-state-update", - async (e, sessionToken: string | null) => { - if (!sessionToken) { - renderUserProfile(null); - return; - } - localStorage.setItem("session_token", sessionToken); - const user = await getUser(sessionToken); - console.log(user); - if (!user) { - localStorage.removeItem("session_token"); - } - renderUserProfile(user); - } - ); - - const sessionToken = localStorage.getItem("session_token"); - if (sessionToken) { - const user = await getUser(sessionToken); - renderUserProfile(user); - } -}); - -const getUser = async (sessionToken: string): Promise => { - return await ipcRenderer.invoke("auth:getUser", sessionToken); -}; - -type User = { - userId: string; - username: string; -}; diff --git a/examples/electron/github-oauth/app/src/types.d.ts b/examples/electron/github-oauth/app/src/types.d.ts deleted file mode 100644 index eae3393f1..000000000 --- a/examples/electron/github-oauth/app/src/types.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Vite -// plugin that tells the Electron app where to look for the Vite-bundled app code (depending on -// whether you're running in development or production). -declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string; -declare const MAIN_WINDOW_VITE_NAME: string; diff --git a/examples/electron/github-oauth/app/tsconfig.json b/examples/electron/github-oauth/app/tsconfig.json deleted file mode 100644 index 5e3519a6b..000000000 --- a/examples/electron/github-oauth/app/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "commonjs", - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "noImplicitAny": true, - "sourceMap": true, - "baseUrl": ".", - "outDir": "dist", - "moduleResolution": "node", - "resolveJsonModule": true - }, - "include": ["src"] -} diff --git a/examples/electron/github-oauth/app/vite.main.config.ts b/examples/electron/github-oauth/app/vite.main.config.ts deleted file mode 100644 index 6814f96f0..000000000 --- a/examples/electron/github-oauth/app/vite.main.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from "vite"; - -// https://vitejs.dev/config -export default defineConfig({ - resolve: { - // Some libs that can run in both Web and Node.js, such as `axios`, we need to tell Vite to build them in Node.js. - browserField: false, - mainFields: ["module", "jsnext:main", "jsnext"] - } -}); diff --git a/examples/electron/github-oauth/app/vite.preload.config.ts b/examples/electron/github-oauth/app/vite.preload.config.ts deleted file mode 100644 index fbf7eda44..000000000 --- a/examples/electron/github-oauth/app/vite.preload.config.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { defineConfig } from "vite"; - -// https://vitejs.dev/config -export default defineConfig({}); diff --git a/examples/electron/github-oauth/app/vite.renderer.config.ts b/examples/electron/github-oauth/app/vite.renderer.config.ts deleted file mode 100644 index fbf7eda44..000000000 --- a/examples/electron/github-oauth/app/vite.renderer.config.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { defineConfig } from "vite"; - -// https://vitejs.dev/config -export default defineConfig({}); diff --git a/examples/electron/github-oauth/server/.env.example b/examples/electron/github-oauth/server/.env.example deleted file mode 100644 index 0e0e5f95b..000000000 --- a/examples/electron/github-oauth/server/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -GITHUB_CLIENT_ID="" -GITHUB_CLIENT_SECRET="" \ No newline at end of file diff --git a/examples/electron/github-oauth/server/.gitignore b/examples/electron/github-oauth/server/.gitignore deleted file mode 100644 index 1dcef2d9f..000000000 --- a/examples/electron/github-oauth/server/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.env \ No newline at end of file diff --git a/examples/electron/github-oauth/server/package.json b/examples/electron/github-oauth/server/package.json deleted file mode 100644 index c7b261fbc..000000000 --- a/examples/electron/github-oauth/server/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scripts": { - "start": "tsx src/index.ts" - }, - "dependencies": { - "@hono/node-server": "^1.1.0", - "@lucia-auth/adapter-sqlite": "latest", - "@lucia-auth/oauth": "latest", - "better-sqlite3": "^8.4.0", - "dotenv": "^16.0.3", - "hono": "^3.6.0", - "lucia": "latest" - }, - "devDependencies": { - "@types/better-sqlite3": "^7.6.3", - "tsx": "^3.12.2" - } -} diff --git a/examples/electron/github-oauth/server/src/app.d.ts b/examples/electron/github-oauth/server/src/app.d.ts deleted file mode 100644 index 343cbac48..000000000 --- a/examples/electron/github-oauth/server/src/app.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// -declare namespace Lucia { - type Auth = import("./auth").Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = {}; -} diff --git a/examples/electron/github-oauth/server/src/auth.ts b/examples/electron/github-oauth/server/src/auth.ts deleted file mode 100644 index b8696b16d..000000000 --- a/examples/electron/github-oauth/server/src/auth.ts +++ /dev/null @@ -1,37 +0,0 @@ -import dotenv from "dotenv"; - -dotenv.config(); - -import { lucia } from "lucia"; -import { hono } from "lucia/middleware"; -import { betterSqlite3 } from "@lucia-auth/adapter-sqlite"; - -import { github } from "@lucia-auth/oauth/providers"; - -import sqlite from "better-sqlite3"; -import fs from "fs"; - -const db = sqlite(":memory:"); -db.exec(fs.readFileSync("src/schema.sql", "utf8")); - -export const auth = lucia({ - env: process.env.NODE_ENV === "production" ? "PROD" : "DEV", - adapter: betterSqlite3(db, { - user: "user", - session: "user_session", - key: "user_key" - }), - middleware: hono(), - getUserAttributes: (data) => { - return { - username: data.username - }; - } -}); - -export type Auth = typeof auth; - -export const githubAuth = github(auth, { - clientId: process.env.GITHUB_CLIENT_ID ?? "", - clientSecret: process.env.GITHUB_CLIENT_SECRET ?? "" -}); diff --git a/examples/electron/github-oauth/server/src/index.ts b/examples/electron/github-oauth/server/src/index.ts deleted file mode 100644 index f4e823a57..000000000 --- a/examples/electron/github-oauth/server/src/index.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { serve } from "@hono/node-server"; -import { Hono } from "hono"; -import { getCookie, setCookie } from "hono/cookie"; -import { auth, githubAuth } from "./auth"; -import { OAuthRequestError } from "@lucia-auth/oauth"; - -const app = new Hono(); - -app.get("/user", async (c) => { - const authRequest = auth.handleRequest(c); - const session = await authRequest.validateBearerToken(); - if (!session) { - return c.newResponse(null, 401); - } - return c.json(session.user); -}); - -app.get("/login/github", async (c) => { - const [authorizationUrl, state] = await githubAuth.getAuthorizationUrl(); - setCookie(c, "github_oauth_state", state, { - path: "/", - maxAge: 60 * 10, - httpOnly: true, - secure: process.env.NODE_ENV === "production" - }); - return c.redirect(authorizationUrl.toString()); -}); - -app.get("/login/github/callback", async (c) => { - const url = new URL(c.req.url); - const code = url.searchParams.get("code"); - if (!code) return c.newResponse(null, 400); - const state = url.searchParams.get("state"); - const storedState = getCookie(c, "github_oauth_state"); - if (!state || !storedState || state !== storedState) { - return c.newResponse(null, 400); - } - try { - const { getExistingUser, githubUser, createUser } = - await githubAuth.validateCallback(code); - let user = await getExistingUser(); - if (!user) { - user = await createUser({ - attributes: { - username: githubUser.login - } - }); - } - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - return c.redirect( - `electron-app://login?session_token=${session.sessionId}` - ); - } catch (e) { - console.log(e); - if (e instanceof OAuthRequestError) { - // invalid code - return c.newResponse(null, 400); - } - return c.newResponse(null, 500); - } -}); - -app.post("/logout", async (c) => { - const authRequest = auth.handleRequest(c); - const session = await authRequest.validateBearerToken(); - if (!session) return c.newResponse(null, 401); - await auth.invalidateSession(session.sessionId); - return c.newResponse(null, 200); -}); - -serve(app); diff --git a/examples/electron/github-oauth/server/src/schema.sql b/examples/electron/github-oauth/server/src/schema.sql deleted file mode 100644 index 013ddfbc3..000000000 --- a/examples/electron/github-oauth/server/src/schema.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE user ( - id VARCHAR(15) PRIMARY KEY, - username VARCHAR(31) NOT NULL -); -CREATE TABLE user_key ( - id VARCHAR(255) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - hashed_password VARCHAR(255), - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE user_session ( - id VARCHAR(127) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - active_expires BIGINT NOT NULL, - idle_expires BIGINT NOT NULL, - FOREIGN KEY (user_id) REFERENCES user(id) -); \ No newline at end of file diff --git a/examples/expo/github-oauth/README.md b/examples/expo/github-oauth/README.md deleted file mode 100644 index 18e590934..000000000 --- a/examples/expo/github-oauth/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# GitHub OAuth example with Lucia and Expo - -This example has 2 parts: the Expo application and the TS server with Lucia. Uses SQLite3 with `better-sqlite3` as the database. - -## App - -Inside `app` directory. We recommend using `npm` instead of `pnpm`. - -```bash -# install dependencies -npm i - -# start ios simulator -npm run ios - -# start android simulator -npm run android -``` - -## Server - -Inside `server` directory. Make sure to setup your `.env` file. - -```bash -# install dependencies -pnpm i - -# run dev server on port 3000 -pnpm start -``` - -## Setup GitHub OAuth - -[Create a new GitHub OAuth app](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app). The redirect uri should be set to `localhost:5173/login/github/callback`. Copy and paste the client id and secret into `.env`. - -```bash -GITHUB_CLIENT_ID="" -GITHUB_CLIENT_SECRET="" -``` - -## User schema - -| id | type | -| ---------- | -------- | -| `id` | `string` | -| `username` | `string` | diff --git a/examples/expo/github-oauth/app/.gitignore b/examples/expo/github-oauth/app/.gitignore deleted file mode 100644 index 05647d55c..000000000 --- a/examples/expo/github-oauth/app/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files - -# dependencies -node_modules/ - -# Expo -.expo/ -dist/ -web-build/ - -# Native -*.orig.* -*.jks -*.p8 -*.p12 -*.key -*.mobileprovision - -# Metro -.metro-health-check* - -# debug -npm-debug.* -yarn-debug.* -yarn-error.* - -# macOS -.DS_Store -*.pem - -# local env files -.env*.local - -# typescript -*.tsbuildinfo diff --git a/examples/expo/github-oauth/app/App.tsx b/examples/expo/github-oauth/app/App.tsx deleted file mode 100644 index 6648e9eb1..000000000 --- a/examples/expo/github-oauth/app/App.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { StatusBar } from "expo-status-bar"; -import { Button, StyleSheet, Text, View } from "react-native"; -import * as Browser from "expo-web-browser"; -import * as Linking from "expo-linking"; -import * as SecureStore from "expo-secure-store"; -import { useEffect, useState } from "react"; - -export default function App() { - const [currentUser, setCurrentUser] = useState(null); - - const signIn = async () => { - const result = await Browser.openAuthSessionAsync( - "http://localhost:3000/login/github", - "exp://192.168.2.100:8081/login" - ); - if (result.type !== "success") return; - const url = Linking.parse(result.url); - const sessionToken = url.queryParams?.session_token?.toString() ?? null; - if (!sessionToken) return; - const user = await getUser(sessionToken); - await SecureStore.setItemAsync("session_token", sessionToken); - setCurrentUser(user); - }; - - const signOut = async () => { - const sessionToken = await SecureStore.getItemAsync("session_token"); - const response = await fetch("http://localhost:3000/logout", { - method: "POST", - headers: { - Authorization: `Bearer ${sessionToken}` - } - }); - if (!response.ok) return; - await SecureStore.deleteItemAsync("session_token"); - setCurrentUser(null); - }; - - useEffect(() => { - const setup = async () => { - const sessionToken = await SecureStore.getItemAsync("session_token"); - let user: User | null = null; - if (sessionToken) { - user = await getUser(sessionToken); - if (!user) { - await SecureStore.deleteItemAsync("session_token"); - } - } else { - await SecureStore.deleteItemAsync("session_token"); - } - setCurrentUser(user); - }; - setup(); - }, []); - - return ( - - - GitHub OAuth with Lucia - - - {currentUser ? JSON.stringify(currentUser, null, 2) : "(none)"} - - - - - diff --git a/examples/other/login-throttling-device-cookie/src/index.ts b/examples/other/login-throttling-device-cookie/src/index.ts deleted file mode 100644 index c3b597080..000000000 --- a/examples/other/login-throttling-device-cookie/src/index.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { serve } from "@hono/node-server"; -import { Hono } from "hono"; -import { setCookie, getCookie } from "hono/cookie"; -import { generateRandomString } from "lucia/utils"; -import fs from "fs/promises"; - -const app = new Hono(); - -const loginTimeout = new Map< - string, - { - timeoutUntil: number; - timeoutSeconds: number; - } ->(); - -const deviceCookie = new Map< - string, - { - username: string; - attempts: number; - } ->(); - -app.get("/", async (c) => { - const html = await fs.readFile("src/index.html"); - return c.html(html.toString()); -}); - -app.post("/", async (c) => { - const { username, password } = await c.req.parseBody(); - if (typeof username !== "string" || username.length < 1) { - return c.text("Invalid username", 400); - } - if (password !== "invalid" && password !== "valid") { - return c.text("Invalid request body", 400); - } - const storedDeviceCookieId = getCookie(c, "device_cookie") ?? null; - const validDeviceCookie = isValidateDeviceCookie( - storedDeviceCookieId, - username - ); - if (!validDeviceCookie) { - setCookie(c, "device_cookie", "", { - path: "/", - secure: false, // true for production - maxAge: 0, - httpOnly: true - }); - const storedTimeout = loginTimeout.get(username) ?? null; - const timeoutUntil = storedTimeout?.timeoutUntil ?? 0; - if (Date.now() < timeoutUntil) { - return c.text( - `Too many requests - wait ${Math.floor( - (timeoutUntil - Date.now()) / 1000 - )} seconds`, - 400 - ); - } - const timeoutSeconds = storedTimeout ? storedTimeout.timeoutSeconds * 2 : 1; - loginTimeout.set(username, { - timeoutUntil: Date.now() + timeoutSeconds * 1000, - timeoutSeconds - }); - if (password === "invalid") { - return c.json( - `Invalid credentials - timed out for ${timeoutSeconds} seconds`, - 400 - ); - } - loginTimeout.delete(username); - } else { - if (password === "invalid") { - return c.json(`Invalid credentials`, 400); - } - } - const newDeviceCookieId = generateRandomString(40); - deviceCookie.set(newDeviceCookieId, { - username, - attempts: 0 - }); - setCookie(c, "device_cookie", newDeviceCookieId, { - path: "/", - secure: false, // true for production - maxAge: 60 * 60 * 24 * 365, // 1 year - httpOnly: true - }); - return c.text("Success - throttling reset"); -}); - -const isValidateDeviceCookie = ( - deviceCookieId: string | null, - username: string -) => { - if (!deviceCookieId) return false; - const deviceCookieAttributes = deviceCookie.get(deviceCookieId) ?? null; - if (!deviceCookieAttributes) return false; - const currentAttempts = deviceCookieAttributes.attempts + 1; - if (currentAttempts > 5 || deviceCookieAttributes.username !== username) { - deviceCookie.delete(deviceCookieId); - return false; - } - deviceCookie.set(deviceCookieId, { - username, - attempts: currentAttempts - }); - return true; -}; - -serve(app); diff --git a/examples/other/login-throttling/README.md b/examples/other/login-throttling/README.md deleted file mode 100644 index cd6fca34a..000000000 --- a/examples/other/login-throttling/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Login throttling - -``` -npm install -npm run start -``` - -``` -open http://localhost:3000 -``` diff --git a/examples/other/login-throttling/package.json b/examples/other/login-throttling/package.json deleted file mode 100644 index 8544a539e..000000000 --- a/examples/other/login-throttling/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "scripts": { - "start": "tsx src/index.ts" - }, - "dependencies": { - "@hono/node-server": "^1.1.0", - "hono": "^3.4.1" - }, - "devDependencies": { - "@types/node": "^20.4.9", - "tsx": "^3.12.2" - } -} diff --git a/examples/other/login-throttling/src/index.html b/examples/other/login-throttling/src/index.html deleted file mode 100644 index e298ef011..000000000 --- a/examples/other/login-throttling/src/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - Rate limiting demo - - -

Login throttling demo

-
- - -
- Password - -
- -
-
- -
- - diff --git a/examples/other/login-throttling/src/index.ts b/examples/other/login-throttling/src/index.ts deleted file mode 100644 index 45f01081c..000000000 --- a/examples/other/login-throttling/src/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { serve } from "@hono/node-server"; -import { Hono } from "hono"; -import fs from "fs/promises"; - -const app = new Hono(); - -const loginTimeout = new Map< - string, - { - timeoutUntil: number; - timeoutSeconds: number; - } ->(); - -app.get("/", async (c) => { - const html = await fs.readFile("src/index.html"); - return c.html(html.toString()); -}); - -app.post("/", async (c) => { - const { username, password } = await c.req.parseBody(); - if (typeof username !== "string" || username.length < 1) { - return c.text("Invalid username", 400); - } - if (password !== "invalid" && password !== "valid") { - return c.text("Invalid request body", 400); - } - const storedTimeout = loginTimeout.get(username); - const timeoutUntil = storedTimeout?.timeoutUntil ?? 0; - if (Date.now() < timeoutUntil) { - return c.text( - `Too many requests - wait ${Math.floor( - (timeoutUntil - Date.now()) / 1000 - )} seconds`, - 400 - ); - } - const timeoutSeconds = storedTimeout ? storedTimeout.timeoutSeconds * 2 : 1; - loginTimeout.set(username, { - timeoutUntil: Date.now() + timeoutSeconds * 1000, - timeoutSeconds - }); - if (password === "invalid") { - return c.json( - `Invalid credentials - timed out for ${timeoutSeconds} seconds`, - 400 - ); - } - loginTimeout.delete(username); - return c.text("Success - throttling reset"); -}); - -serve(app); diff --git a/examples/solidstart/github-oauth/.env.example b/examples/solidstart/github-oauth/.env.example deleted file mode 100644 index 0e0e5f95b..000000000 --- a/examples/solidstart/github-oauth/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -GITHUB_CLIENT_ID="" -GITHUB_CLIENT_SECRET="" \ No newline at end of file diff --git a/examples/solidstart/github-oauth/.gitignore b/examples/solidstart/github-oauth/.gitignore deleted file mode 100644 index de90b58df..000000000 --- a/examples/solidstart/github-oauth/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ - -dist -.solid -.output -.vercel -.netlify -netlify - -# Environment -.env -.env*.local - -# dependencies -/node_modules - -# IDEs and editors -/.idea -.project -.classpath -*.launch -.settings/ - -# Temp -gitignore - -# System Files -.DS_Store -Thumbs.db - -main.db \ No newline at end of file diff --git a/examples/solidstart/github-oauth/README.md b/examples/solidstart/github-oauth/README.md deleted file mode 100644 index cc8a2dfe0..000000000 --- a/examples/solidstart/github-oauth/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# GitHub OAuth example with Lucia and SolidStart - -This example uses `better-sqlite3`. - -```bash -# install dependencies -pnpm i - -# run dev server -pnpm dev -``` - -## Runtime - -This example is built for Node.js 20. If you're using Node.js 16/18, un-comment the following lines in `auth/lucia.ts`: - -```ts -// import "lucia/polyfill/node"; -``` - -## User schema - -| id | type | unique | -| ---------- | -------- | :----: | -| `id` | `string` | | -| `username` | `string` | ✓ | diff --git a/examples/solidstart/github-oauth/package.json b/examples/solidstart/github-oauth/package.json deleted file mode 100644 index 3642b051a..000000000 --- a/examples/solidstart/github-oauth/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "github-oauth", - "description": "GitHub OAuth example with Lucia and SolidStart", - "scripts": { - "dev": "solid-start dev", - "build": "solid-start build", - "start": "solid-start start" - }, - "type": "module", - "devDependencies": { - "@types/node": "^18.11.18", - "esbuild": "^0.14.54", - "postcss": "^8.4.21", - "solid-start-node": "^0.2.19", - "typescript": "^4.9.4", - "vite": "^4.4.6" - }, - "dependencies": { - "@lucia-auth/adapter-sqlite": "latest", - "@lucia-auth/oauth": "latest", - "@solidjs/meta": "^0.28.2", - "@solidjs/router": "^0.8.2", - "better-sqlite3": "^8.4.0", - "lucia": "latest", - "solid-js": "^1.7.8", - "solid-start": "^0.2.30", - "undici": "^5.15.1" - } -} diff --git a/examples/solidstart/github-oauth/public/favicon.ico b/examples/solidstart/github-oauth/public/favicon.ico deleted file mode 100644 index fb282da0719ef6ab4c1732df93be6216b0d85520..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 664 zcmV;J0%!e+P)m9ebk1R zejT~~6f_`?;`cEd!+`7(hw@%%2;?RN8gX-L?z6cM( zKoG@&w+0}f@Pfvwc+deid)qgE!L$ENKYjViZC_Zcr>L(`2oXUT8f0mRQ(6-=HN_Ai zeBBEz3WP+1Cw`m!49Wf!MnZzp5bH8VkR~BcJ1s-j90TAS2Yo4j!J|KodxYR%3Numw zA?gq6e`5@!W~F$_De3yt&uspo&2yLb$(NwcPPI-4LGc!}HdY%jfq@AFs8LiZ4k(p} zZ!c9o+qbWYs-Mg zgdyTALzJX&7QXHdI_DPTFL33;w}88{e6Zk)MX0kN{3DX9uz#O_L58&XRH$Nvvu;fO zf&)7@?C~$z1K<>j0ga$$MIg+5xN;eQ?1-CA=`^Y169@Ab6!vcaNP=hxfKN%@Ly^R* zK1iv*s1Yl6_dVyz8>ZqYhz6J4|3fQ@2LQeX@^%W(B~8>=MoEmBEGGD1;gHXlpX>!W ym)!leA2L@`cpb^hy)P75=I!`pBYxP7<2VfQ3j76qLgzIA0000 -declare namespace Lucia { - type Auth = import("./auth/lucia").Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = {}; -} diff --git a/examples/solidstart/github-oauth/src/auth/lucia.ts b/examples/solidstart/github-oauth/src/auth/lucia.ts deleted file mode 100644 index 149b804ef..000000000 --- a/examples/solidstart/github-oauth/src/auth/lucia.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { lucia } from "lucia"; -import { web } from "lucia/middleware"; -import { betterSqlite3 } from "@lucia-auth/adapter-sqlite"; -import { github } from "@lucia-auth/oauth/providers"; -// import "lucia/polyfill/node"; - -import sqlite from "better-sqlite3"; -import fs from "fs"; - -const db = sqlite(":memory:"); -db.exec(fs.readFileSync("schema.sql", "utf8")); - -export const auth = lucia({ - adapter: betterSqlite3(db, { - user: "user", - session: "user_session", - key: "user_key" - }), - env: process.env.NODE_ENV === "development" ? "DEV" : "PROD", - middleware: web(), - sessionCookie: { - expires: false - }, - getUserAttributes: (data) => { - return { - githubUsername: data.username - }; - } -}); - -export const githubAuth = github(auth, { - clientId: process.env.GITHUB_CLIENT_ID ?? "", - clientSecret: process.env.GITHUB_CLIENT_SECRET ?? "" -}); - -export type Auth = typeof auth; diff --git a/examples/solidstart/github-oauth/src/entry-client.tsx b/examples/solidstart/github-oauth/src/entry-client.tsx deleted file mode 100644 index 942284855..000000000 --- a/examples/solidstart/github-oauth/src/entry-client.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { mount, StartClient } from "solid-start/entry-client"; - -mount(() => , document); diff --git a/examples/solidstart/github-oauth/src/entry-server.tsx b/examples/solidstart/github-oauth/src/entry-server.tsx deleted file mode 100644 index 20e987de2..000000000 --- a/examples/solidstart/github-oauth/src/entry-server.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { - createHandler, - renderAsync, - StartServer -} from "solid-start/entry-server"; - -export default createHandler( - renderAsync((event) => ) -); diff --git a/examples/solidstart/github-oauth/src/root.css b/examples/solidstart/github-oauth/src/root.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/solidstart/github-oauth/src/root.css +++ /dev/null @@ -1,10 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.error { - color: red; -} diff --git a/examples/solidstart/github-oauth/src/root.tsx b/examples/solidstart/github-oauth/src/root.tsx deleted file mode 100644 index 8e662e15b..000000000 --- a/examples/solidstart/github-oauth/src/root.tsx +++ /dev/null @@ -1,36 +0,0 @@ -// @refresh reload -import { Suspense } from "solid-js"; -import { - Body, - ErrorBoundary, - FileRoutes, - Head, - Html, - Meta, - Routes, - Scripts, - Title -} from "solid-start"; -import "./root.css"; - -export default function Root() { - return ( - - - GitHub OAuth with Lucia - - - - - - - - - - - - - - - ); -} diff --git a/examples/solidstart/github-oauth/src/routes/[...404].tsx b/examples/solidstart/github-oauth/src/routes/[...404].tsx deleted file mode 100644 index 2238ae98d..000000000 --- a/examples/solidstart/github-oauth/src/routes/[...404].tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Title } from "solid-start"; -import { HttpStatusCode } from "solid-start/server"; - -export default function NotFound() { - return ( -
- Not Found - -

Page Not Found

-
- ); -} diff --git a/examples/solidstart/github-oauth/src/routes/index.tsx b/examples/solidstart/github-oauth/src/routes/index.tsx deleted file mode 100644 index 6e5fa5417..000000000 --- a/examples/solidstart/github-oauth/src/routes/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useRouteData } from "solid-start"; -import { - ServerError, - createServerAction$, - createServerData$, - redirect -} from "solid-start/server"; -import { auth } from "~/auth/lucia"; - -export const routeData = () => { - return createServerData$(async (_, event) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (!session) { - return redirect("/login") as never; - } - return session.user; - }); -}; - -const Page = () => { - const user = useRouteData(); - const [_, { Form }] = createServerAction$(async (_, event) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (!session) { - throw new ServerError("Unauthorized", { - status: 401 - }); - } - await auth.invalidateSession(session.sessionId); // invalidate session - const sessionCookie = auth.createSessionCookie(null); - return new Response(null, { - status: 302, - headers: { - Location: "/login", - "Set-Cookie": sessionCookie.serialize() - } - }); - }); - return ( - <> -

Profile

-

User id: {user()?.userId}

-

GitHub username: {user()?.githubUsername}

-
- -
- - ); -}; - -export default Page; diff --git a/examples/solidstart/github-oauth/src/routes/login/github/callback.ts b/examples/solidstart/github-oauth/src/routes/login/github/callback.ts deleted file mode 100644 index 79a0f1260..000000000 --- a/examples/solidstart/github-oauth/src/routes/login/github/callback.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { auth, githubAuth } from "~/auth/lucia"; -import { OAuthRequestError } from "@lucia-auth/oauth"; -import { parseCookie, redirect } from "solid-start"; - -import type { APIEvent } from "solid-start"; - -export const GET = async (event: APIEvent) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (session) { - return redirect("/", 302); // redirect to profile page - } - const cookies = parseCookie(event.request.headers.get("Cookie") ?? ""); - const storedState = cookies.github_oauth_state; - const url = new URL(event.request.url); - const state = url.searchParams.get("state"); - const code = url.searchParams.get("code"); - // validate state - if (!storedState || !state || storedState !== state || !code) { - return new Response(null, { - status: 400 - }); - } - try { - const { getExistingUser, githubUser, createUser } = - await githubAuth.validateCallback(code); - - const getUser = async () => { - const existingUser = await getExistingUser(); - if (existingUser) return existingUser; - const user = await createUser({ - attributes: { - username: githubUser.login - } - }); - return user; - }; - - const user = await getUser(); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - const sessionCookie = auth.createSessionCookie(session); - return new Response(null, { - status: 302, - headers: { - Location: "/", - "Set-Cookie": sessionCookie.serialize() - } - }); - } catch (e) { - if (e instanceof OAuthRequestError) { - // invalid code - return new Response(null, { - status: 400 - }); - } - return new Response(null, { - status: 500 - }); - } -}; diff --git a/examples/solidstart/github-oauth/src/routes/login/github/index.ts b/examples/solidstart/github-oauth/src/routes/login/github/index.ts deleted file mode 100644 index 0d6966b28..000000000 --- a/examples/solidstart/github-oauth/src/routes/login/github/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { auth, githubAuth } from "~/auth/lucia"; -import { redirect } from "solid-start"; -import { serializeCookie } from "solid-start"; - -import type { APIEvent } from "solid-start"; - -export const GET = async (event: APIEvent) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (session) { - return redirect("/", 302); // redirect to profile page - } - const [url, state] = await githubAuth.getAuthorizationUrl(); - return new Response(null, { - status: 302, - headers: { - Location: url.toString(), - "Set-Cookie": serializeCookie("github_oauth_state", state, { - httpOnly: true, - secure: process.env.NODE_ENV === "production", - path: "/", - maxAge: 60 * 60 - }) - } - }); -}; diff --git a/examples/solidstart/github-oauth/src/routes/login/index.tsx b/examples/solidstart/github-oauth/src/routes/login/index.tsx deleted file mode 100644 index fc258502e..000000000 --- a/examples/solidstart/github-oauth/src/routes/login/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { auth } from "~/auth/lucia"; -import { createServerData$, redirect } from "solid-start/server"; - -export const routeData = () => { - return createServerData$(async (_, event) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (session) { - return redirect("/"); - } - }); -}; - -const Page = () => { - return ( - <> -

Sign in

- Sign in with GitHub - - ); -}; - -export default Page; diff --git a/examples/solidstart/github-oauth/tsconfig.json b/examples/solidstart/github-oauth/tsconfig.json deleted file mode 100644 index 632cf03f4..000000000 --- a/examples/solidstart/github-oauth/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "node", - "jsxImportSource": "solid-js", - "jsx": "preserve", - "strict": true, - "types": ["solid-start/env"], - "baseUrl": "./", - "paths": { - "~/*": ["./src/*"] - } - } -} diff --git a/examples/solidstart/github-oauth/vite.config.ts b/examples/solidstart/github-oauth/vite.config.ts deleted file mode 100644 index 6c36d4e1f..000000000 --- a/examples/solidstart/github-oauth/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import solid from "solid-start/vite"; -import { defineConfig } from "vite"; - -export default defineConfig({ - plugins: [solid()] -}); diff --git a/examples/solidstart/username-and-password/.gitignore b/examples/solidstart/username-and-password/.gitignore deleted file mode 100644 index de90b58df..000000000 --- a/examples/solidstart/username-and-password/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ - -dist -.solid -.output -.vercel -.netlify -netlify - -# Environment -.env -.env*.local - -# dependencies -/node_modules - -# IDEs and editors -/.idea -.project -.classpath -*.launch -.settings/ - -# Temp -gitignore - -# System Files -.DS_Store -Thumbs.db - -main.db \ No newline at end of file diff --git a/examples/solidstart/username-and-password/README.md b/examples/solidstart/username-and-password/README.md deleted file mode 100644 index baa23d890..000000000 --- a/examples/solidstart/username-and-password/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Username & password example with Lucia and SolidStart - -This example uses `better-sqlite3`. - -```bash -# install dependencies -pnpm i - -# run dev server -pnpm dev -``` - -## Runtime - -This example is built for Node.js 20. If you're using Node.js 16/18, un-comment the following lines in `auth/lucia.ts`: - -```ts -// import "lucia/polyfill/node"; -``` - -## User schema - -| id | type | unique | -| ---------- | -------- | :----: | -| `id` | `string` | | -| `username` | `string` | ✓ | diff --git a/examples/solidstart/username-and-password/package.json b/examples/solidstart/username-and-password/package.json deleted file mode 100644 index 7e4ee33f2..000000000 --- a/examples/solidstart/username-and-password/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "username-and-password", - "description": "Username & password example with Lucia and SolidStart", - "scripts": { - "dev": "solid-start dev", - "build": "solid-start build", - "start": "solid-start start" - }, - "type": "module", - "devDependencies": { - "@types/node": "^18.11.18", - "esbuild": "^0.14.54", - "postcss": "^8.4.21", - "solid-start-node": "^0.2.19", - "typescript": "^4.9.4", - "vite": "^4.4.6" - }, - "dependencies": { - "@lucia-auth/adapter-sqlite": "latest", - "@solidjs/meta": "^0.28.2", - "@solidjs/router": "^0.8.2", - "better-sqlite3": "^8.4.0", - "lucia": "latest", - "solid-js": "^1.7.8", - "solid-start": "^0.2.30", - "undici": "^5.15.1" - } -} diff --git a/examples/solidstart/username-and-password/public/favicon.ico b/examples/solidstart/username-and-password/public/favicon.ico deleted file mode 100644 index fb282da0719ef6ab4c1732df93be6216b0d85520..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 664 zcmV;J0%!e+P)m9ebk1R zejT~~6f_`?;`cEd!+`7(hw@%%2;?RN8gX-L?z6cM( zKoG@&w+0}f@Pfvwc+deid)qgE!L$ENKYjViZC_Zcr>L(`2oXUT8f0mRQ(6-=HN_Ai zeBBEz3WP+1Cw`m!49Wf!MnZzp5bH8VkR~BcJ1s-j90TAS2Yo4j!J|KodxYR%3Numw zA?gq6e`5@!W~F$_De3yt&uspo&2yLb$(NwcPPI-4LGc!}HdY%jfq@AFs8LiZ4k(p} zZ!c9o+qbWYs-Mg zgdyTALzJX&7QXHdI_DPTFL33;w}88{e6Zk)MX0kN{3DX9uz#O_L58&XRH$Nvvu;fO zf&)7@?C~$z1K<>j0ga$$MIg+5xN;eQ?1-CA=`^Y169@Ab6!vcaNP=hxfKN%@Ly^R* zK1iv*s1Yl6_dVyz8>ZqYhz6J4|3fQ@2LQeX@^%W(B~8>=MoEmBEGGD1;gHXlpX>!W ym)!leA2L@`cpb^hy)P75=I!`pBYxP7<2VfQ3j76qLgzIA0000 -declare namespace Lucia { - type Auth = import("./auth/lucia").Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = {}; -} diff --git a/examples/solidstart/username-and-password/src/auth/lucia.ts b/examples/solidstart/username-and-password/src/auth/lucia.ts deleted file mode 100644 index a57779f80..000000000 --- a/examples/solidstart/username-and-password/src/auth/lucia.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { lucia } from "lucia"; -import { web } from "lucia/middleware"; -import { betterSqlite3 } from "@lucia-auth/adapter-sqlite"; -// import "lucia/polyfill/node"; - -import sqlite from "better-sqlite3"; -import fs from "fs"; - -const db = sqlite(":memory:"); -db.exec(fs.readFileSync("schema.sql", "utf8")); - -export const auth = lucia({ - adapter: betterSqlite3(db, { - user: "user", - session: "user_session", - key: "user_key" - }), - env: process.env.NODE_ENV === "development" ? "DEV" : "PROD", - middleware: web(), - sessionCookie: { - expires: false - }, - getUserAttributes: (data) => { - return { - username: data.username - }; - } -}); - -export type Auth = typeof auth; diff --git a/examples/solidstart/username-and-password/src/entry-client.tsx b/examples/solidstart/username-and-password/src/entry-client.tsx deleted file mode 100644 index 942284855..000000000 --- a/examples/solidstart/username-and-password/src/entry-client.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { mount, StartClient } from "solid-start/entry-client"; - -mount(() => , document); diff --git a/examples/solidstart/username-and-password/src/entry-server.tsx b/examples/solidstart/username-and-password/src/entry-server.tsx deleted file mode 100644 index 20e987de2..000000000 --- a/examples/solidstart/username-and-password/src/entry-server.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { - createHandler, - renderAsync, - StartServer -} from "solid-start/entry-server"; - -export default createHandler( - renderAsync((event) => ) -); diff --git a/examples/solidstart/username-and-password/src/root.css b/examples/solidstart/username-and-password/src/root.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/solidstart/username-and-password/src/root.css +++ /dev/null @@ -1,10 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.error { - color: red; -} diff --git a/examples/solidstart/username-and-password/src/root.tsx b/examples/solidstart/username-and-password/src/root.tsx deleted file mode 100644 index 1c18a8a2d..000000000 --- a/examples/solidstart/username-and-password/src/root.tsx +++ /dev/null @@ -1,36 +0,0 @@ -// @refresh reload -import { Suspense } from "solid-js"; -import { - Body, - ErrorBoundary, - FileRoutes, - Head, - Html, - Meta, - Routes, - Scripts, - Title -} from "solid-start"; -import "./root.css"; - -export default function Root() { - return ( - - - Username and password auth with Lucia - - - - - - - - - - - - - - - ); -} diff --git a/examples/solidstart/username-and-password/src/routes/[...404].tsx b/examples/solidstart/username-and-password/src/routes/[...404].tsx deleted file mode 100644 index 2238ae98d..000000000 --- a/examples/solidstart/username-and-password/src/routes/[...404].tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Title } from "solid-start"; -import { HttpStatusCode } from "solid-start/server"; - -export default function NotFound() { - return ( -
- Not Found - -

Page Not Found

-
- ); -} diff --git a/examples/solidstart/username-and-password/src/routes/index.tsx b/examples/solidstart/username-and-password/src/routes/index.tsx deleted file mode 100644 index 9ccc10a4e..000000000 --- a/examples/solidstart/username-and-password/src/routes/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useRouteData } from "solid-start"; -import { - ServerError, - createServerAction$, - createServerData$, - redirect -} from "solid-start/server"; -import { auth } from "~/auth/lucia"; - -export const routeData = () => { - return createServerData$(async (_, event) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (!session) { - return redirect("/login") as never; - } - return session.user; - }); -}; - -const Page = () => { - const user = useRouteData(); - const [_, { Form }] = createServerAction$(async (_, event) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (!session) { - throw new ServerError("Unauthorized", { - status: 401 - }); - } - await auth.invalidateSession(session.sessionId); // invalidate session - const sessionCookie = auth.createSessionCookie(null); - return new Response(null, { - status: 302, - headers: { - Location: "/login", - "Set-Cookie": sessionCookie.serialize() - } - }); - }); - return ( - <> -

Profile

-

User id: {user()?.userId}

-

Username: {user()?.username}

-
- -
- - ); -}; - -export default Page; diff --git a/examples/solidstart/username-and-password/src/routes/login.tsx b/examples/solidstart/username-and-password/src/routes/login.tsx deleted file mode 100644 index 65a598a99..000000000 --- a/examples/solidstart/username-and-password/src/routes/login.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { auth } from "~/auth/lucia"; -import { - ServerError, - createServerAction$, - createServerData$, - redirect -} from "solid-start/server"; -import { LuciaError } from "lucia"; -import { Show } from "solid-js"; -import { A } from "solid-start"; - -export const routeData = () => { - return createServerData$(async (_, event) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (session) { - return redirect("/"); - } - }); -}; - -const Page = () => { - const [enrolling, { Form }] = createServerAction$( - async (formData: FormData) => { - const username = formData.get("username"); - const password = formData.get("password"); - // basic check - if ( - typeof username !== "string" || - username.length < 1 || - username.length > 31 - ) { - throw new ServerError("Invalid username"); - } - if ( - typeof password !== "string" || - password.length < 1 || - password.length > 255 - ) { - throw new ServerError("Invalid password"); - } - try { - // find user by key - // and validate password - const key = await auth.useKey( - "username", - username.toLowerCase(), - password - ); - const session = await auth.createSession({ - userId: key.userId, - attributes: {} - }); - const sessionCookie = auth.createSessionCookie(session); - // set cookie and redirect - return new Response(null, { - status: 302, - headers: { - Location: "/", - "Set-Cookie": sessionCookie.serialize() - } - }); - } catch (e) { - if ( - e instanceof LuciaError && - (e.message === "AUTH_INVALID_KEY_ID" || - e.message === "AUTH_INVALID_PASSWORD") - ) { - // user does not exist - // or invalid password - throw new ServerError("Incorrect username or password"); - } - throw new ServerError("An unknown error occurred"); - } - } - ); - return ( - <> -

Sign in

-
- - -
- - -
- -
- -

{enrolling.error.message}

; -
- Create an account - - ); -}; - -export default Page; diff --git a/examples/solidstart/username-and-password/src/routes/signup.tsx b/examples/solidstart/username-and-password/src/routes/signup.tsx deleted file mode 100644 index 56d359df3..000000000 --- a/examples/solidstart/username-and-password/src/routes/signup.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Show } from "solid-js"; -import { auth } from "~/auth/lucia"; -import { A } from "solid-start"; -import { ServerError } from "solid-start/server"; -import { SqliteError } from "better-sqlite3"; - -import { - createServerAction$, - createServerData$, - redirect -} from "solid-start/server"; - -export const routeData = () => { - return createServerData$(async (_, event) => { - const authRequest = auth.handleRequest(event.request); - const session = await authRequest.validate(); - if (session) { - return redirect("/"); - } - }); -}; - -const Page = () => { - const [enrolling, { Form }] = createServerAction$( - async (formData: FormData) => { - const username = formData.get("username"); - const password = formData.get("password"); - if ( - typeof username !== "string" || - username.length < 4 || - username.length > 31 - ) { - throw new ServerError("Invalid username"); - } - if ( - typeof password !== "string" || - password.length < 6 || - password.length > 255 - ) { - throw new ServerError("Invalid password"); - } - try { - const user = await auth.createUser({ - key: { - providerId: "username", // auth method - providerUserId: username.toLowerCase(), // unique id when using "username" auth method - password // hashed by Lucia - }, - attributes: { - username - } - }); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - const sessionCookie = auth.createSessionCookie(session); - // set cookie and redirect - return new Response(null, { - status: 302, - headers: { - Location: "/", - "Set-Cookie": sessionCookie.serialize() - } - }); - } catch (e) { - // check for unique constraint error in user table - if (e instanceof SqliteError && e.code === "SQLITE_CONSTRAINT_UNIQUE") { - throw new ServerError("Username already taken"); - } - throw new ServerError("An unknown error occurred", { - status: 500 - }); - } - } - ); - return ( - <> -

Sign up

-
- - -
- - -
- -
- -

{enrolling.error.message}

; -
- Sign in - - ); -}; - -export default Page; diff --git a/examples/solidstart/username-and-password/tsconfig.json b/examples/solidstart/username-and-password/tsconfig.json deleted file mode 100644 index 632cf03f4..000000000 --- a/examples/solidstart/username-and-password/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "node", - "jsxImportSource": "solid-js", - "jsx": "preserve", - "strict": true, - "types": ["solid-start/env"], - "baseUrl": "./", - "paths": { - "~/*": ["./src/*"] - } - } -} diff --git a/examples/solidstart/username-and-password/vite.config.ts b/examples/solidstart/username-and-password/vite.config.ts deleted file mode 100644 index 6c36d4e1f..000000000 --- a/examples/solidstart/username-and-password/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import solid from "solid-start/vite"; -import { defineConfig } from "vite"; - -export default defineConfig({ - plugins: [solid()] -}); diff --git a/examples/sveltekit/email-and-password/.eslintignore b/examples/sveltekit/email-and-password/.eslintignore deleted file mode 100644 index 38972655f..000000000 --- a/examples/sveltekit/email-and-password/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example - -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock diff --git a/examples/sveltekit/email-and-password/.eslintrc.cjs b/examples/sveltekit/email-and-password/.eslintrc.cjs deleted file mode 100644 index ebc19589f..000000000 --- a/examples/sveltekit/email-and-password/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - root: true, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:svelte/recommended', - 'prettier' - ], - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], - parserOptions: { - sourceType: 'module', - ecmaVersion: 2020, - extraFileExtensions: ['.svelte'] - }, - env: { - browser: true, - es2017: true, - node: true - }, - overrides: [ - { - files: ['*.svelte'], - parser: 'svelte-eslint-parser', - parserOptions: { - parser: '@typescript-eslint/parser' - } - } - ] -}; diff --git a/examples/sveltekit/email-and-password/.gitignore b/examples/sveltekit/email-and-password/.gitignore deleted file mode 100644 index 07442e394..000000000 --- a/examples/sveltekit/email-and-password/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example -vite.config.js.timestamp-* -vite.config.ts.timestamp-* - -main.db \ No newline at end of file diff --git a/examples/sveltekit/email-and-password/.npmrc b/examples/sveltekit/email-and-password/.npmrc deleted file mode 100644 index 0c05da457..000000000 --- a/examples/sveltekit/email-and-password/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -engine-strict=true -resolution-mode=highest diff --git a/examples/sveltekit/email-and-password/.prettierignore b/examples/sveltekit/email-and-password/.prettierignore deleted file mode 100644 index 38972655f..000000000 --- a/examples/sveltekit/email-and-password/.prettierignore +++ /dev/null @@ -1,13 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example - -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock diff --git a/examples/sveltekit/email-and-password/.prettierrc b/examples/sveltekit/email-and-password/.prettierrc deleted file mode 100644 index a77fddea9..000000000 --- a/examples/sveltekit/email-and-password/.prettierrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "useTabs": true, - "singleQuote": true, - "trailingComma": "none", - "printWidth": 100, - "plugins": ["prettier-plugin-svelte"], - "pluginSearchDirs": ["."], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] -} diff --git a/examples/sveltekit/email-and-password/README.md b/examples/sveltekit/email-and-password/README.md deleted file mode 100644 index 1b3cc8ee7..000000000 --- a/examples/sveltekit/email-and-password/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Email & password example with Lucia and SvelteKit - -This example uses SQLite3 with `better-sqlite3`. - -```bash -# install dependencies -pnpm i - -# run dev server -pnpm dev -``` - -## User schema - -| id | type | unique | -| ---------------- | ----------------------- | :----: | -| `id` | `string` | | -| `email` | `string` | ✓ | -| `email_verified` | `number` (as `boolean`) | ✓ | diff --git a/examples/sveltekit/email-and-password/package.json b/examples/sveltekit/email-and-password/package.json deleted file mode 100644 index e4b41c15f..000000000 --- a/examples/sveltekit/email-and-password/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "email-and-password", - "description": "Email & password example with Lucia and SvelteKit", - "version": "0.0.1", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --plugin-search-dir . --check . && eslint .", - "format": "prettier --plugin-search-dir . --write ." - }, - "dependencies": { - "@lucia-auth/adapter-sqlite": "latest", - "better-sqlite3": "^8.4.0", - "kysely": "^0.25.0", - "lucia": "latest" - }, - "devDependencies": { - "@sveltejs/adapter-auto": "^2.0.0", - "@sveltejs/kit": "^1.20.4", - "@types/better-sqlite3": "^7.6.3", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", - "eslint": "^8.28.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-svelte": "^2.30.0", - "prettier": "^2.8.0", - "prettier-plugin-svelte": "^2.10.1", - "svelte": "^4.0.0", - "svelte-check": "^3.4.3", - "tslib": "^2.4.1", - "typescript": "^5.0.0", - "vite": "^4.3.6" - }, - "type": "module" -} diff --git a/examples/sveltekit/email-and-password/schema.sql b/examples/sveltekit/email-and-password/schema.sql deleted file mode 100644 index 9df84fdaa..000000000 --- a/examples/sveltekit/email-and-password/schema.sql +++ /dev/null @@ -1,28 +0,0 @@ -CREATE TABLE user ( - id VARCHAR(15) PRIMARY KEY, - email VARCHAR(31) NOT NULL UNIQUE, - email_verified INTEGER NOT NULL -); -CREATE TABLE user_key ( - id VARCHAR(255) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - hashed_password VARCHAR(255), - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE user_session ( - id VARCHAR(127) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - active_expires BIGINT NOT NULL, - idle_expires BIGINT NOT NULL, - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE email_verification_token ( - id VARCHAR(63) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - expires BIGINT NOT NULL -); -CREATE TABLE password_reset_token ( - id VARCHAR(63) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - expires BIGINT NOT NULL -); \ No newline at end of file diff --git a/examples/sveltekit/email-and-password/src/app.css b/examples/sveltekit/email-and-password/src/app.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/sveltekit/email-and-password/src/app.css +++ /dev/null @@ -1,10 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.error { - color: red; -} diff --git a/examples/sveltekit/email-and-password/src/app.d.ts b/examples/sveltekit/email-and-password/src/app.d.ts deleted file mode 100644 index 04a0a5774..000000000 --- a/examples/sveltekit/email-and-password/src/app.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -// See https://kit.svelte.dev/docs/types#app -// for information about these interfaces -declare global { - namespace App { - interface Locals { - auth: import('lucia').AuthRequest; - } - } -} - -/// -declare global { - namespace Lucia { - type Auth = import('$lib/server/lucia').Auth; - type DatabaseUserAttributes = { - email: string; - email_verified: number; - }; - type DatabaseSessionAttributes = Record; - } -} - -export {}; diff --git a/examples/sveltekit/email-and-password/src/app.html b/examples/sveltekit/email-and-password/src/app.html deleted file mode 100644 index effe0d0d2..000000000 --- a/examples/sveltekit/email-and-password/src/app.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/examples/sveltekit/email-and-password/src/hooks.server.ts b/examples/sveltekit/email-and-password/src/hooks.server.ts deleted file mode 100644 index e60673b6a..000000000 --- a/examples/sveltekit/email-and-password/src/hooks.server.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import type { Handle } from '@sveltejs/kit'; - -export const handle: Handle = async ({ event, resolve }) => { - // we can pass `event` because we used the SvelteKit middleware - event.locals.auth = auth.handleRequest(event); - return await resolve(event); -}; diff --git a/examples/sveltekit/email-and-password/src/lib/server/db.ts b/examples/sveltekit/email-and-password/src/lib/server/db.ts deleted file mode 100644 index 1974a8a7b..000000000 --- a/examples/sveltekit/email-and-password/src/lib/server/db.ts +++ /dev/null @@ -1,49 +0,0 @@ -import sqlite from 'better-sqlite3'; -import fs from 'fs'; -import { Kysely, SqliteDialect } from 'kysely'; - -import type { ColumnType } from 'kysely'; - -export const sqliteDatabase = sqlite(':memory:'); -sqliteDatabase.exec(fs.readFileSync('schema.sql', 'utf8')); - -const dialect = new SqliteDialect({ - database: sqliteDatabase -}); - -export const db = new Kysely({ - dialect -}); - -type Database = { - user: UserTable; - user_session: SessionTable; - user_key: KeyTable; - email_verification_token: VerificationTokenTable; - password_reset_token: VerificationTokenTable; -}; - -type UserTable = { - id: string; - email: string; - email_verified: number; -}; - -type SessionTable = { - id: string; - user_id: string; - idle_expires: ColumnType; - active_expires: ColumnType; -}; - -type KeyTable = { - id: string; - user_id: string; - hashed_password: null | string; -}; - -type VerificationTokenTable = { - id: string; - user_id: string; - expires: ColumnType; -}; diff --git a/examples/sveltekit/email-and-password/src/lib/server/email.ts b/examples/sveltekit/email-and-password/src/lib/server/email.ts deleted file mode 100644 index 1e8e815f8..000000000 --- a/examples/sveltekit/email-and-password/src/lib/server/email.ts +++ /dev/null @@ -1,16 +0,0 @@ -export const sendEmailVerificationLink = async (token: string) => { - const url = `http://localhost:5173/email-verification/${token}`; - console.log(`Your email verification link: ${url}`); -}; - -export const sendPasswordResetLink = async (token: string) => { - const url = `http://localhost:5173/password-reset/${token}`; - console.log(`Your password reset link: ${url}`); -}; - -export const isValidEmail = (maybeEmail: unknown): maybeEmail is string => { - if (typeof maybeEmail !== 'string') return false; - if (maybeEmail.length > 255) return false; - const emailRegexp = /^.+@.+$/; // [one or more character]@[one or more character] - return emailRegexp.test(maybeEmail); -}; diff --git a/examples/sveltekit/email-and-password/src/lib/server/lucia.ts b/examples/sveltekit/email-and-password/src/lib/server/lucia.ts deleted file mode 100644 index e24ad281c..000000000 --- a/examples/sveltekit/email-and-password/src/lib/server/lucia.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { lucia } from 'lucia'; -import { betterSqlite3 } from '@lucia-auth/adapter-sqlite'; -import { sveltekit } from 'lucia/middleware'; -import { dev } from '$app/environment'; - -import { sqliteDatabase } from './db'; - -export const auth = lucia({ - adapter: betterSqlite3(sqliteDatabase, { - user: 'user', - session: 'user_session', - key: 'user_key' - }), - middleware: sveltekit(), - env: dev ? 'DEV' : 'PROD', - getUserAttributes: (data) => { - return { - email: data.email, - emailVerified: Boolean(data.email_verified) - }; - } -}); - -export type Auth = typeof auth; diff --git a/examples/sveltekit/email-and-password/src/lib/server/token.ts b/examples/sveltekit/email-and-password/src/lib/server/token.ts deleted file mode 100644 index 730b1c027..000000000 --- a/examples/sveltekit/email-and-password/src/lib/server/token.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { db } from './db.js'; -import { generateRandomString, isWithinExpiration } from 'lucia/utils'; - -const EXPIRES_IN = 1000 * 60 * 60 * 2; // 2 hours - -export const generateEmailVerificationToken = async (userId: string) => { - const storedUserTokens = await db - .selectFrom('email_verification_token') - .selectAll() - .where('user_id', '=', userId) - .execute(); - if (storedUserTokens.length > 0) { - const reusableStoredToken = storedUserTokens.find((token) => { - // check if expiration is within 1 hour - // and reuse the token if true - return isWithinExpiration(Number(token.expires) - EXPIRES_IN / 2); - }); - if (reusableStoredToken) return reusableStoredToken.id; - } - const token = generateRandomString(63); - await db - .insertInto('email_verification_token') - .values({ - id: token, - expires: new Date().getTime() + EXPIRES_IN, - user_id: userId - }) - .executeTakeFirst(); - return token; -}; - -export const validateEmailVerificationToken = async (token: string) => { - const storedToken = await db.transaction().execute(async (trx) => { - const storedToken = await trx - .selectFrom('email_verification_token') - .selectAll() - .where('id', '=', token) - .executeTakeFirst(); - if (!storedToken) throw new Error('Invalid token'); - await trx - .deleteFrom('email_verification_token') - .where('user_id', '=', storedToken.user_id) - .executeTakeFirst(); - return storedToken; - }); - const tokenExpires = Number(storedToken.expires); // bigint => number conversion - if (!isWithinExpiration(tokenExpires)) { - throw new Error('Expired token'); - } - return storedToken.user_id; -}; - -export const generatePasswordResetToken = async (userId: string) => { - const storedUserTokens = await db - .selectFrom('password_reset_token') - .selectAll() - .where('user_id', '=', userId) - .execute(); - if (storedUserTokens.length > 0) { - const reusableStoredToken = storedUserTokens.find((token) => { - // check if expiration is within 1 hour - // and reuse the token if true - return isWithinExpiration(Number(token.expires) - EXPIRES_IN / 2); - }); - if (reusableStoredToken) return reusableStoredToken.id; - } - const token = generateRandomString(63); - await db - .insertInto('password_reset_token') - .values({ - id: token, - expires: new Date().getTime() + EXPIRES_IN, - user_id: userId - }) - .executeTakeFirst(); - return token; -}; - -export const validatePasswordResetToken = async (token: string) => { - const storedToken = await db.transaction().execute(async (trx) => { - const storedToken = await trx - .selectFrom('password_reset_token') - .selectAll() - .where('id', '=', token) - .executeTakeFirst(); - if (!storedToken) throw new Error('Invalid token'); - await trx.deleteFrom('password_reset_token').where('id', '=', token).executeTakeFirst(); - return storedToken; - }); - const tokenExpires = Number(storedToken.expires); // bigint => number conversion - if (!isWithinExpiration(tokenExpires)) { - throw new Error('Expired token'); - } - return storedToken.user_id; -}; - -export const isValidPasswordResetToken = async (token: string) => { - const storedToken = await db - .selectFrom('password_reset_token') - .selectAll() - .where('id', '=', token) - .executeTakeFirst(); - if (!storedToken) return false; - const tokenExpires = Number(storedToken.expires); // bigint => number conversion - if (!isWithinExpiration(tokenExpires)) { - return false; - } - return true; -}; diff --git a/examples/sveltekit/email-and-password/src/routes/+layout.svelte b/examples/sveltekit/email-and-password/src/routes/+layout.svelte deleted file mode 100644 index 0e7ad9250..000000000 --- a/examples/sveltekit/email-and-password/src/routes/+layout.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - - - Email & password auth with Lucia - - diff --git a/examples/sveltekit/email-and-password/src/routes/+page.server.ts b/examples/sveltekit/email-and-password/src/routes/+page.server.ts deleted file mode 100644 index 8ddc4c1b4..000000000 --- a/examples/sveltekit/email-and-password/src/routes/+page.server.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { fail, redirect } from '@sveltejs/kit'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) throw redirect(302, '/login'); - if (!session.user.emailVerified) { - throw redirect(302, '/email-verification'); - } - return { - userId: session.user.userId, - email: session.user.email - }; -}; - -export const actions: Actions = { - logout: async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) return fail(401); - await auth.invalidateSession(session.sessionId); // invalidate session - locals.auth.setSession(null); // remove cookie - throw redirect(302, '/login'); // redirect to login page - } -}; diff --git a/examples/sveltekit/email-and-password/src/routes/+page.svelte b/examples/sveltekit/email-and-password/src/routes/+page.svelte deleted file mode 100644 index 3f671b7fe..000000000 --- a/examples/sveltekit/email-and-password/src/routes/+page.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -

Profile

-

User id: {data.userId}

-

Email: {data.email}

-
- -
\ No newline at end of file diff --git a/examples/sveltekit/email-and-password/src/routes/email-verification/+page.server.ts b/examples/sveltekit/email-and-password/src/routes/email-verification/+page.server.ts deleted file mode 100644 index 46fe28a3e..000000000 --- a/examples/sveltekit/email-and-password/src/routes/email-verification/+page.server.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { redirect, fail } from '@sveltejs/kit'; -import { generateEmailVerificationToken } from '$lib/server/token'; -import { sendEmailVerificationLink } from '$lib/server/email'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) throw redirect(302, '/login'); - if (session.user.emailVerified) { - throw redirect(302, '/'); - } - return {}; -}; - -export const actions: Actions = { - default: async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) throw redirect(302, '/login'); - if (session.user.emailVerified) { - throw redirect(302, '/'); - } - try { - const token = await generateEmailVerificationToken(session.user.userId); - await sendEmailVerificationLink(token); - return { - success: true - }; - } catch { - return fail(500, { - message: 'An unknown error occurred' - }); - } - } -}; diff --git a/examples/sveltekit/email-and-password/src/routes/email-verification/+page.svelte b/examples/sveltekit/email-and-password/src/routes/email-verification/+page.svelte deleted file mode 100644 index 5eb626600..000000000 --- a/examples/sveltekit/email-and-password/src/routes/email-verification/+page.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - -

Email verification

-

Your email verification link was sent to your inbox (i.e. console).

-

Resend verification link

-
- -
-{#if form?.success} -

Your verification link was resent

-{/if} diff --git a/examples/sveltekit/email-and-password/src/routes/email-verification/[token]/+server.ts b/examples/sveltekit/email-and-password/src/routes/email-verification/[token]/+server.ts deleted file mode 100644 index 8825a5ecc..000000000 --- a/examples/sveltekit/email-and-password/src/routes/email-verification/[token]/+server.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { validateEmailVerificationToken } from '$lib/server/token'; - -import type { RequestHandler } from './$types'; - -export const GET: RequestHandler = async ({ params, locals }) => { - const { token } = params; - try { - const userId = await validateEmailVerificationToken(token); - const user = await auth.getUser(userId); - await auth.invalidateAllUserSessions(user.userId); - await auth.updateUserAttributes(user.userId, { - email_verified: Number(true) - }); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - locals.auth.setSession(session); - return new Response(null, { - status: 302, - headers: { - Location: '/' - } - }); - } catch { - return new Response('Invalid email verification link', { - status: 400 - }); - } -}; diff --git a/examples/sveltekit/email-and-password/src/routes/login/+page.server.ts b/examples/sveltekit/email-and-password/src/routes/login/+page.server.ts deleted file mode 100644 index 51d273f0b..000000000 --- a/examples/sveltekit/email-and-password/src/routes/login/+page.server.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { LuciaError } from 'lucia'; -import { fail, redirect } from '@sveltejs/kit'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (session) { - if (!session.user.emailVerified) throw redirect(302, '/email-verification'); - throw redirect(302, '/'); - } - return {}; -}; - -export const actions: Actions = { - default: async ({ request, locals }) => { - const formData = await request.formData(); - const email = formData.get('email'); - const password = formData.get('password'); - // basic check - if (typeof email !== 'string' || email.length < 1 || email.length > 255) { - return fail(400, { - message: 'Invalid email' - }); - } - if (typeof password !== 'string' || password.length < 1 || password.length > 255) { - return fail(400, { - message: 'Invalid password' - }); - } - try { - // find user by key - // and validate password - const key = await auth.useKey('email', email.toLowerCase(), password); - const session = await auth.createSession({ - userId: key.userId, - attributes: {} - }); - locals.auth.setSession(session); // set session cookie - } catch (e) { - if ( - e instanceof LuciaError && - (e.message === 'AUTH_INVALID_KEY_ID' || e.message === 'AUTH_INVALID_PASSWORD') - ) { - // user does not exist - // or invalid password - return fail(400, { - message: 'Incorrect email or password' - }); - } - return fail(500, { - message: 'An unknown error occurred' - }); - } - // redirect to profile page - // make sure you don't throw inside a try/catch block! - throw redirect(302, '/'); - } -}; diff --git a/examples/sveltekit/email-and-password/src/routes/login/+page.svelte b/examples/sveltekit/email-and-password/src/routes/login/+page.svelte deleted file mode 100644 index b74ffa5f3..000000000 --- a/examples/sveltekit/email-and-password/src/routes/login/+page.svelte +++ /dev/null @@ -1,21 +0,0 @@ - - -

Sign in

-
- -
- -
- -
-{#if form?.message} -

{form.message}

-{/if} -Reset password -Create an account diff --git a/examples/sveltekit/email-and-password/src/routes/password-reset/+page.server.ts b/examples/sveltekit/email-and-password/src/routes/password-reset/+page.server.ts deleted file mode 100644 index 0be53aae9..000000000 --- a/examples/sveltekit/email-and-password/src/routes/password-reset/+page.server.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { fail } from '@sveltejs/kit'; -import { db } from '$lib/server/db'; -import { generatePasswordResetToken } from '$lib/server/token'; -import { isValidEmail, sendPasswordResetLink } from '$lib/server/email'; - -import type { Actions } from './$types'; - -export const actions: Actions = { - default: async ({ request }) => { - const formData = await request.formData(); - const email = formData.get('email'); - // basic check - if (!isValidEmail(email)) { - return fail(400, { - message: 'Invalid email' - }); - } - try { - const storedUser = await db - .selectFrom('user') - .selectAll() - .where('email', '=', email) - .executeTakeFirst(); - if (!storedUser) { - return fail(400, { - message: 'User does not exist' - }); - } - const user = auth.transformDatabaseUser(storedUser); - const token = await generatePasswordResetToken(user.userId); - await sendPasswordResetLink(token); - return { - success: true - }; - } catch (e) { - return fail(500, { - message: 'An unknown error occurred' - }); - } - } -}; diff --git a/examples/sveltekit/email-and-password/src/routes/password-reset/+page.svelte b/examples/sveltekit/email-and-password/src/routes/password-reset/+page.svelte deleted file mode 100644 index 20c666df2..000000000 --- a/examples/sveltekit/email-and-password/src/routes/password-reset/+page.svelte +++ /dev/null @@ -1,21 +0,0 @@ - - -

Reset password

-
- -
- -
-{#if form?.message} -

{form.message}

-{/if} -{#if form?.success} -

Your password reset link was sent to your inbox

-{/if} -Sign in diff --git a/examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.server.ts b/examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.server.ts deleted file mode 100644 index 3a483859c..000000000 --- a/examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.server.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { fail, redirect } from '@sveltejs/kit'; -import { isValidPasswordResetToken, validatePasswordResetToken } from '$lib/server/token'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ params }) => { - const { token } = params; - const validToken = await isValidPasswordResetToken(token); - if (!validToken) { - throw redirect(302, '/password-reset'); - } - return {}; -}; - -export const actions: Actions = { - default: async ({ request, params, locals }) => { - const formData = await request.formData(); - const password = formData.get('password'); - // basic check - if (typeof password !== 'string' || password.length < 6 || password.length > 255) { - return fail(400, { - message: 'Invalid password' - }); - } - try { - const { token } = params; - const userId = await validatePasswordResetToken(token); - let user = await auth.getUser(userId); - await auth.invalidateAllUserSessions(user.userId); - await auth.updateKeyPassword('email', user.email, password); - if (!user.emailVerified) { - user = await auth.updateUserAttributes(user.userId, { - email_verified: Number(true) - }); - } - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - locals.auth.setSession(session); - } catch (e) { - return fail(400, { - message: 'Invalid or expired password reset link' - }); - } - throw redirect(302, '/'); - } -}; diff --git a/examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.svelte b/examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.svelte deleted file mode 100644 index e9967e8b8..000000000 --- a/examples/sveltekit/email-and-password/src/routes/password-reset/[token]/+page.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - -

Reset password

-
- -
- -
-{#if form?.message} -

{form.message}

-{/if} diff --git a/examples/sveltekit/email-and-password/src/routes/signup/+page.server.ts b/examples/sveltekit/email-and-password/src/routes/signup/+page.server.ts deleted file mode 100644 index 7e08af7bb..000000000 --- a/examples/sveltekit/email-and-password/src/routes/signup/+page.server.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { fail, redirect } from '@sveltejs/kit'; -import { SqliteError } from 'better-sqlite3'; -import { generateEmailVerificationToken } from '$lib/server/token'; -import { isValidEmail, sendEmailVerificationLink } from '$lib/server/email'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (session) { - if (!session.user.emailVerified) throw redirect(302, '/email-verification'); - throw redirect(302, '/'); - } - return {}; -}; - -export const actions: Actions = { - default: async ({ request, locals }) => { - const formData = await request.formData(); - const email = formData.get('email'); - const password = formData.get('password'); - // basic check - if (!isValidEmail(email)) { - return fail(400, { - message: 'Invalid email' - }); - } - if (typeof password !== 'string' || password.length < 6 || password.length > 255) { - return fail(400, { - message: 'Invalid password' - }); - } - try { - const user = await auth.createUser({ - key: { - providerId: 'email', // auth method - providerUserId: email.toLowerCase(), // unique id when using "email" auth method - password // hashed by Lucia - }, - attributes: { - email: email.toLowerCase(), - email_verified: Number(false) - } - }); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - locals.auth.setSession(session); // set session cookie - const token = await generateEmailVerificationToken(user.userId); - await sendEmailVerificationLink(token); - } catch (e) { - // check for unique constraint error in user table - if (e instanceof SqliteError && e.code === 'SQLITE_CONSTRAINT_UNIQUE') { - return fail(400, { - message: 'Account already exists' - }); - } - return fail(500, { - message: 'An unknown error occurred' - }); - } - // redirect to - // make sure you don't throw inside a try/catch block! - throw redirect(302, '/email-verification'); - } -}; diff --git a/examples/sveltekit/email-and-password/src/routes/signup/+page.svelte b/examples/sveltekit/email-and-password/src/routes/signup/+page.svelte deleted file mode 100644 index b616401e3..000000000 --- a/examples/sveltekit/email-and-password/src/routes/signup/+page.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -

Sign up

-
- -
- -
- -
-{#if form?.message} -

{form.message}

-{/if} -Sign in diff --git a/examples/sveltekit/email-and-password/static/favicon.png b/examples/sveltekit/email-and-password/static/favicon.png deleted file mode 100644 index 825b9e65af7c104cfb07089bb28659393b4f2097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH -declare global { - namespace Lucia { - type Auth = import('$lib/server/lucia').Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = Record; - } -} - -export {}; diff --git a/examples/sveltekit/github-oauth/src/app.html b/examples/sveltekit/github-oauth/src/app.html deleted file mode 100644 index effe0d0d2..000000000 --- a/examples/sveltekit/github-oauth/src/app.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/examples/sveltekit/github-oauth/src/hooks.server.ts b/examples/sveltekit/github-oauth/src/hooks.server.ts deleted file mode 100644 index e60673b6a..000000000 --- a/examples/sveltekit/github-oauth/src/hooks.server.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import type { Handle } from '@sveltejs/kit'; - -export const handle: Handle = async ({ event, resolve }) => { - // we can pass `event` because we used the SvelteKit middleware - event.locals.auth = auth.handleRequest(event); - return await resolve(event); -}; diff --git a/examples/sveltekit/github-oauth/src/lib/server/lucia.ts b/examples/sveltekit/github-oauth/src/lib/server/lucia.ts deleted file mode 100644 index e61e1cf56..000000000 --- a/examples/sveltekit/github-oauth/src/lib/server/lucia.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { lucia } from 'lucia'; -import { betterSqlite3 } from '@lucia-auth/adapter-sqlite'; -import { sveltekit } from 'lucia/middleware'; -import { github } from '@lucia-auth/oauth/providers'; -import { dev } from '$app/environment'; -import { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } from '$env/static/private'; - -import sqlite from 'better-sqlite3'; -import fs from 'fs'; - -const db = sqlite(':memory:'); -db.exec(fs.readFileSync('schema.sql', 'utf8')); - -export const auth = lucia({ - adapter: betterSqlite3(db, { - user: 'user', - session: 'user_session', - key: 'user_key' - }), - middleware: sveltekit(), - env: dev ? 'DEV' : 'PROD', - getUserAttributes: (data) => { - return { - githubUsername: data.username - }; - } -}); - -export const githubAuth = github(auth, { - clientId: GITHUB_CLIENT_ID, - clientSecret: GITHUB_CLIENT_SECRET -}); - -export type Auth = typeof auth; diff --git a/examples/sveltekit/github-oauth/src/routes/+layout.svelte b/examples/sveltekit/github-oauth/src/routes/+layout.svelte deleted file mode 100644 index 465e8cbee..000000000 --- a/examples/sveltekit/github-oauth/src/routes/+layout.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - - - GitHub OAuth with Lucia - - diff --git a/examples/sveltekit/github-oauth/src/routes/+page.server.ts b/examples/sveltekit/github-oauth/src/routes/+page.server.ts deleted file mode 100644 index 25f3e8541..000000000 --- a/examples/sveltekit/github-oauth/src/routes/+page.server.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { fail, redirect } from '@sveltejs/kit'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) throw redirect(302, '/login'); - return { - userId: session.user.userId, - githubUsername: session.user.githubUsername - }; -}; - -export const actions: Actions = { - logout: async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) return fail(401); - await auth.invalidateSession(session.sessionId); // invalidate session - locals.auth.setSession(null); // remove cookie - throw redirect(302, '/login'); // redirect to login page - } -}; diff --git a/examples/sveltekit/github-oauth/src/routes/+page.svelte b/examples/sveltekit/github-oauth/src/routes/+page.svelte deleted file mode 100644 index 2dc324a56..000000000 --- a/examples/sveltekit/github-oauth/src/routes/+page.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -

Profile

-

User id: {data.userId}

-

GitHub username: {data.githubUsername}

-
- -
\ No newline at end of file diff --git a/examples/sveltekit/github-oauth/src/routes/login/+page.server.ts b/examples/sveltekit/github-oauth/src/routes/login/+page.server.ts deleted file mode 100644 index dffb4b41a..000000000 --- a/examples/sveltekit/github-oauth/src/routes/login/+page.server.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { redirect } from '@sveltejs/kit'; - -export const load = async ({ locals }) => { - const session = await locals.auth.validate(); - if (session) throw redirect(302, '/'); - return {}; -}; diff --git a/examples/sveltekit/github-oauth/src/routes/login/+page.svelte b/examples/sveltekit/github-oauth/src/routes/login/+page.svelte deleted file mode 100644 index 2c7930d73..000000000 --- a/examples/sveltekit/github-oauth/src/routes/login/+page.svelte +++ /dev/null @@ -1,2 +0,0 @@ -

Sign in

-Sign in with GitHub \ No newline at end of file diff --git a/examples/sveltekit/github-oauth/src/routes/login/github/+server.ts b/examples/sveltekit/github-oauth/src/routes/login/github/+server.ts deleted file mode 100644 index 1d153d54d..000000000 --- a/examples/sveltekit/github-oauth/src/routes/login/github/+server.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { dev } from '$app/environment'; -import { githubAuth } from '$lib/server/lucia.js'; - -export const GET = async ({ cookies, locals }) => { - const session = await locals.auth.validate(); - if (session) { - return new Response(null, { - status: 302, - headers: { - Location: '/' - } - }); - } - const [url, state] = await githubAuth.getAuthorizationUrl(); - cookies.set('github_oauth_state', state, { - httpOnly: true, - secure: !dev, - path: '/', - maxAge: 60 * 60 - }); - return new Response(null, { - status: 302, - headers: { - Location: url.toString() - } - }); -}; diff --git a/examples/sveltekit/github-oauth/src/routes/login/github/callback/+server.ts b/examples/sveltekit/github-oauth/src/routes/login/github/callback/+server.ts deleted file mode 100644 index 80a20a296..000000000 --- a/examples/sveltekit/github-oauth/src/routes/login/github/callback/+server.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { auth, githubAuth } from '$lib/server/lucia.js'; -import { OAuthRequestError } from '@lucia-auth/oauth'; - -export const GET = async ({ url, cookies, locals }) => { - const session = await locals.auth.validate(); - if (session) { - return new Response(null, { - status: 302, - headers: { - Location: '/' - } - }); - } - const storedState = cookies.get('github_oauth_state'); - const state = url.searchParams.get('state'); - const code = url.searchParams.get('code'); - // validate state - if (!storedState || !state || storedState !== state || !code) { - return new Response(null, { - status: 400 - }); - } - try { - const { getExistingUser, githubUser, createUser } = await githubAuth.validateCallback(code); - - const getUser = async () => { - const existingUser = await getExistingUser(); - if (existingUser) return existingUser; - const user = await createUser({ - attributes: { - username: githubUser.login - } - }); - return user; - }; - - const user = await getUser(); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - locals.auth.setSession(session); - return new Response(null, { - status: 302, - headers: { - Location: '/' - } - }); - } catch (e) { - if (e instanceof OAuthRequestError) { - // invalid code - return new Response(null, { - status: 400 - }); - } - return new Response(null, { - status: 500 - }); - } -}; diff --git a/examples/sveltekit/github-oauth/static/favicon.png b/examples/sveltekit/github-oauth/static/favicon.png deleted file mode 100644 index 825b9e65af7c104cfb07089bb28659393b4f2097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH -declare global { - namespace Lucia { - type Auth = import('$lib/server/lucia').Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = Record; - } -} - -export {}; diff --git a/examples/sveltekit/username-and-password/src/app.html b/examples/sveltekit/username-and-password/src/app.html deleted file mode 100644 index effe0d0d2..000000000 --- a/examples/sveltekit/username-and-password/src/app.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/examples/sveltekit/username-and-password/src/hooks.server.ts b/examples/sveltekit/username-and-password/src/hooks.server.ts deleted file mode 100644 index e60673b6a..000000000 --- a/examples/sveltekit/username-and-password/src/hooks.server.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import type { Handle } from '@sveltejs/kit'; - -export const handle: Handle = async ({ event, resolve }) => { - // we can pass `event` because we used the SvelteKit middleware - event.locals.auth = auth.handleRequest(event); - return await resolve(event); -}; diff --git a/examples/sveltekit/username-and-password/src/lib/server/lucia.ts b/examples/sveltekit/username-and-password/src/lib/server/lucia.ts deleted file mode 100644 index 3ad6191f0..000000000 --- a/examples/sveltekit/username-and-password/src/lib/server/lucia.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { lucia } from 'lucia'; -import { betterSqlite3 } from '@lucia-auth/adapter-sqlite'; -import { sveltekit } from 'lucia/middleware'; -import { dev } from '$app/environment'; - -import sqlite from 'better-sqlite3'; -import fs from 'fs'; - -const db = sqlite(':memory:'); -db.exec(fs.readFileSync('schema.sql', 'utf8')); - -export const auth = lucia({ - adapter: betterSqlite3(db, { - user: 'user', - session: 'user_session', - key: 'user_key' - }), - middleware: sveltekit(), - env: dev ? 'DEV' : 'PROD', - getUserAttributes: (data) => { - return { - username: data.username - }; - } -}); - -export type Auth = typeof auth; diff --git a/examples/sveltekit/username-and-password/src/routes/+layout.svelte b/examples/sveltekit/username-and-password/src/routes/+layout.svelte deleted file mode 100644 index be4ea1301..000000000 --- a/examples/sveltekit/username-and-password/src/routes/+layout.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - - - Username & password auth with Lucia - - diff --git a/examples/sveltekit/username-and-password/src/routes/+page.server.ts b/examples/sveltekit/username-and-password/src/routes/+page.server.ts deleted file mode 100644 index 57caf5ae9..000000000 --- a/examples/sveltekit/username-and-password/src/routes/+page.server.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { fail, redirect } from '@sveltejs/kit'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) throw redirect(302, '/login'); - return { - userId: session.user.userId, - username: session.user.username - }; -}; - -export const actions: Actions = { - logout: async ({ locals }) => { - const session = await locals.auth.validate(); - if (!session) return fail(401); - await auth.invalidateSession(session.sessionId); // invalidate session - locals.auth.setSession(null); // remove cookie - throw redirect(302, '/login'); // redirect to login page - } -}; diff --git a/examples/sveltekit/username-and-password/src/routes/+page.svelte b/examples/sveltekit/username-and-password/src/routes/+page.svelte deleted file mode 100644 index 6a3f98ba2..000000000 --- a/examples/sveltekit/username-and-password/src/routes/+page.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -

Profile

-

User id: {data.userId}

-

Username: {data.username}

-
- -
\ No newline at end of file diff --git a/examples/sveltekit/username-and-password/src/routes/login/+page.server.ts b/examples/sveltekit/username-and-password/src/routes/login/+page.server.ts deleted file mode 100644 index 9fde412b8..000000000 --- a/examples/sveltekit/username-and-password/src/routes/login/+page.server.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { LuciaError } from 'lucia'; -import { fail, redirect } from '@sveltejs/kit'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (session) throw redirect(302, '/'); - return {}; -}; - -export const actions: Actions = { - default: async ({ request, locals }) => { - const formData = await request.formData(); - const username = formData.get('username'); - const password = formData.get('password'); - // basic check - if (typeof username !== 'string' || username.length < 1 || username.length > 31) { - return fail(400, { - message: 'Invalid username' - }); - } - if (typeof password !== 'string' || password.length < 1 || password.length > 255) { - return fail(400, { - message: 'Invalid password' - }); - } - try { - // find user by key - // and validate password - const key = await auth.useKey('username', username.toLowerCase(), password); - const session = await auth.createSession({ - userId: key.userId, - attributes: {} - }); - locals.auth.setSession(session); // set session cookie - } catch (e) { - if ( - e instanceof LuciaError && - (e.message === 'AUTH_INVALID_KEY_ID' || e.message === 'AUTH_INVALID_PASSWORD') - ) { - // user does not exist - // or invalid password - return fail(400, { - message: 'Incorrect username or password' - }); - } - return fail(500, { - message: 'An unknown error occurred' - }); - } - // redirect to - // make sure you don't throw inside a try/catch block! - throw redirect(302, '/'); - } -}; diff --git a/examples/sveltekit/username-and-password/src/routes/login/+page.svelte b/examples/sveltekit/username-and-password/src/routes/login/+page.svelte deleted file mode 100644 index 00d8b57fa..000000000 --- a/examples/sveltekit/username-and-password/src/routes/login/+page.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -

Sign in

-
- -
- -
- -
-{#if form?.message} -

{form.message}

-{/if} -Create an account \ No newline at end of file diff --git a/examples/sveltekit/username-and-password/src/routes/signup/+page.server.ts b/examples/sveltekit/username-and-password/src/routes/signup/+page.server.ts deleted file mode 100644 index b8e25a0b8..000000000 --- a/examples/sveltekit/username-and-password/src/routes/signup/+page.server.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { auth } from '$lib/server/lucia'; -import { fail, redirect } from '@sveltejs/kit'; -import { SqliteError } from 'better-sqlite3'; - -import type { PageServerLoad, Actions } from './$types'; - -export const load: PageServerLoad = async ({ locals }) => { - const session = await locals.auth.validate(); - if (session) throw redirect(302, '/'); - return {}; -}; - -export const actions: Actions = { - default: async ({ request, locals }) => { - const formData = await request.formData(); - const username = formData.get('username'); - const password = formData.get('password'); - // basic check - if (typeof username !== 'string' || username.length < 4 || username.length > 31) { - return fail(400, { - message: 'Invalid username' - }); - } - if (typeof password !== 'string' || password.length < 6 || password.length > 255) { - return fail(400, { - message: 'Invalid password' - }); - } - try { - const user = await auth.createUser({ - key: { - providerId: 'username', // auth method - providerUserId: username.toLowerCase(), // unique id when using "username" auth method - password // hashed by Lucia - }, - attributes: { - username - } - }); - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - locals.auth.setSession(session); // set session cookie - } catch (e) { - // check for unique constraint error in user table - if (e instanceof SqliteError && e.code === 'SQLITE_CONSTRAINT_UNIQUE') { - return fail(400, { - message: 'Username already taken' - }); - } - return fail(500, { - message: 'An unknown error occurred' - }); - } - // redirect to - // make sure you don't throw inside a try/catch block! - throw redirect(302, '/'); - } -}; diff --git a/examples/sveltekit/username-and-password/src/routes/signup/+page.svelte b/examples/sveltekit/username-and-password/src/routes/signup/+page.svelte deleted file mode 100644 index 2039b8ca9..000000000 --- a/examples/sveltekit/username-and-password/src/routes/signup/+page.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -

Sign up

-
- -
- -
- -
-{#if form?.message} -

{form.message}

-{/if} -Sign in diff --git a/examples/sveltekit/username-and-password/static/favicon.png b/examples/sveltekit/username-and-password/static/favicon.png deleted file mode 100644 index 825b9e65af7c104cfb07089bb28659393b4f2097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH - - - - - - Github OAuth with Lucia - - - - -
-

GitHub OAuth with Lucia

-
-

Profile

-
-
-
- - -
-
- - diff --git a/examples/tauri/github-oauth/app/package.json b/examples/tauri/github-oauth/app/package.json deleted file mode 100644 index 5e2fcbc0f..000000000 --- a/examples/tauri/github-oauth/app/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "app", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview", - "tauri": "tauri" - }, - "dependencies": { - "@tauri-apps/api": "^1.4.0" - }, - "devDependencies": { - "@tauri-apps/cli": "^1.4.0", - "vite": "^4.4.4", - "typescript": "^5.0.2" - } -} diff --git a/examples/tauri/github-oauth/app/src-tauri/.gitignore b/examples/tauri/github-oauth/app/src-tauri/.gitignore deleted file mode 100644 index aaaf243f6..000000000 --- a/examples/tauri/github-oauth/app/src-tauri/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ -Cargo.lock - diff --git a/examples/tauri/github-oauth/app/src-tauri/Cargo.toml b/examples/tauri/github-oauth/app/src-tauri/Cargo.toml deleted file mode 100644 index 7b0373eb3..000000000 --- a/examples/tauri/github-oauth/app/src-tauri/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "app" -version = "0.0.0" -description = "A Tauri App" -authors = ["you"] -license = "" -repository = "" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[build-dependencies] -tauri-build = { version = "1.4", features = [] } - -[dependencies] -tauri = { version = "1.4", features = [ "shell-open", "http-request"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -tokio = { version = "1.32.0", features = ["net"] } - -[features] -# this feature is used for production builds or when `devPath` points to the filesystem -# DO NOT REMOVE!! -custom-protocol = ["tauri/custom-protocol"] diff --git a/examples/tauri/github-oauth/app/src-tauri/build.rs b/examples/tauri/github-oauth/app/src-tauri/build.rs deleted file mode 100644 index 795b9b7c8..000000000 --- a/examples/tauri/github-oauth/app/src-tauri/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - tauri_build::build() -} diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/128x128.png b/examples/tauri/github-oauth/app/src-tauri/icons/128x128.png deleted file mode 100644 index 6be5e50e9b9ae84d9e2ee433f32ef446495eaf3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3512 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 diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/128x128@2x.png b/examples/tauri/github-oauth/app/src-tauri/icons/128x128@2x.png deleted file mode 100644 index e81becee571e96f76aa5667f9324c05e5e7a4479..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7012 zcmbVRhd10$wEyl}tP&+^)YVI(cM?|boe*`EAflJ(td=N=)q)^ML`czsM6^|+Bsw9{ zRxcr}zQo#ne((JUZ_b&yGjs0DnR90D=ibkqR5KIZYm{u1003Om*VD290MJzz1VG8I zghNo3$CaQ6(7P8508|YBRS-~E%=({7u!XJ$P&2~u=V}1)R5w-!fO-@a-h~tZ*v|E} z)UConyDt}l7;UoqkF36Q(znu2&;PA10!d*~p4ENpMbz?r+@PQ{MTUb1|7*T6z)FB~ zil2(zBtyMbF>;>;YG>)$qf`!S?sVx|uX~h;#^2)qS-lr5`eB=xj`VYjS8X{eYvqSCp!MVQ+Zp)ah!BOx=<<)3_%H{42A-g}l-uWe_bd zKmuE<1$6Cm4{Ur*DPRCoVkX)`R-k#@gC0(4##3?N&+rs2dc29|tL>p|VuZrAb9JK& zu{fyJ_ck5GVdO`1s(8Q(hzs^@I>vkbt=CxD`%fZW@OrB7f}n7S zw;MjWo)({rDJ~hK-aI$VGS)_z6L!~E>Sw6VryiT=rA^<5<)LCh@l9Q9guNI_1-`wRLpA_?^qeI@{^Zz{+lxCXjoOEdxXE6j- z-}9&QGt)!@Lv$n&M0F*?Hb^el0wLG3ZEh`FC7fc?dC$UOXV;wR?D<@Fx%}@lCaE@K zIe00?Dp@Oh{qg!N38;Yn{)LzJuvpv1zn$1R(Led#p|BoLjY%v((9Ybm z*H%8*p0=q|^Sip^4d*N28NWotn@mYF!A9x=%ax4iXabcaAT^36kx<~Xx_9Z zmX)Zbg@R;9>VW8w!AtFGN20whdPb6jV6zmUw`CA5Y~Jtt{stZLXe@PlM@=iR@?l%lMcTv-0ZzU_U#FCgjGl9SWhR#KYD8+^q?uLyD zO|^I%UB9q-$qloS&)ueZ-L=kPvH{M2=gZgt5NnQWGVW{GIcM9AZ-3@9r3p02?cOQ! z6<-Ax;vK=O(lb6SU&z$FE|NJ7tIQ2V>$uunOUI1U9{mf5g#oJ*fnO^A5o2jQ|85>b zxiFGScj!nQE6RN5JEjpG8HtPtYK%QTar{@da0B~8Gioh}Bu(t?6YSVbRMB;ezkU$dH2D9WD2x=-fhMo+Xrmz_NhjTC>f*Kw4P zCFIf?MYz_(N*>U}tV$}LObr)ZQ6gOh3yM*;Xowm7?{w(iu=5vV?>{(BC8}Eqv&Hmve6M6KY z(yc~_FL9R9AiV<_N~x_e=q`H=P6=SraZcXHy__lEyWKbCwW+zLmR*g;T+5bQuWmnW z>&^mpczmZLymWbQ(`LBo>Awvj&S+_>^0BGOi>j^1<;88Z|(NUz;t&t6tm)8}ZfC3K(_uHgh_ih($^E!prj$VF1Wn zVsVh@d4g6UzEwgH7f?&fm`a=c0VoElycf8Xs>}BwC!_lmvR~NSTP+M8Va5J&-uUw3 zkm&#$BSn~0`#mE<-F`2qy9>v0Hp*8zS_0kb6QKOb&}l7}5u>I^R!nbGvUgg0doF4| zCTlnSV5i=KID}qvz{fliGV6L=u1UX@B@pzlP-D4R9|WhA6reJVbGX0RIQK#A`yvA> zpbj^aklJmQE21PMBO2@`BNvY}Ru`m-*8`2jKR#bzdB^x;KL77ov_G?_n{5&!etI4E zzRj|hqdqqMW7&fn7t0b29wlhUe*?3>72W_0LF*E&57{;b+1JHi{yJkKIgg`H2yUA5 z?ft#B19b`5)ZA1_;&lst06-8%vi;8CpT9_`)n8cNAn-6#A`h60+e*JJNT^)lNbGnpq7O4IT;4OqFpvVOBgHJrdIiISpB_%g}P3%LTXGy{Gxy zU|>bk;iKN2+Vq2m!Fr`0sf>WGq2UyBhw`4Gbn>%gw)JuMf?tn$fF^j)<=6a~jL{=a zvp`UtgTIFmR@_!L=oauo^I!8r3>;?4soM7*aeWL-Do7lWKxD5!%U{UrMaY&Q8LQ&&oMA z(IdMY8o%{Pz4&ljBVA{Q6iyYBk<%}uG|SE)sPNibY9{Z!R|B=RsW50OOUkYYeCF4Y z|AGS>h<7dU18Shbm$?4#ZCMC?Z+^QQAg_+anCE^ruJ{DQSq4`VYI3oT3|$Nt$lDQ8 z)>rz~XD)z?8ZK+c1iBU7imvM8K1-oBO8n5K`ugqxPgByg7T}F9c4s>+Qb|jto;_wMBmB28Ycg=bmpXr_eU%4kv44A0ILV-n;&gI0GBDD1y&W}Uzxl2vlg<_T(41u zfKt8}C6r37nkv?w?odQ*#;_F_Q|rI_MrzNX)93XO;9x`dCUC3RR0C`7GD9X_={|HD zC-3TrtFml2f!SaFV`t=t3|OqAbF(hfio(fnLlT|6beHB=#W{2}0`tXy>>*?4;+7lV zYQC-0agzK56iVxN%#*KT`o zzx!1g@-DB>be(RfI8;iPl%A^g-Yl&xGoVRlsyh`#c6|!`OyLHl3Blgj`*zn0ap0h~!NXz?Zt*&Kj%LpRR zOa6H?3%(Ca8I})0W4*Vq<1w<5&*`d`{d1j&B^7c@*fD)SOGTggpxg1Vo>5K9 zy`8yA+mwS!me^MFCk>Zo`wHm_BDlFEW`W{6?G{dqt!b@fN-@5(Tc}RcyyMHC<*@z7 z(6aB5=3*DXkNYpp_g&%!pE-+2Y`1;=$j5WU8#+HXevdQty3>I~sMJ~c0Pd3kPfuLy z5zDp^(DDVv%S6De;l&gPIdz4DrRf>1oFSGLI;I1{O&>stES{Ay?3A%f!>@m;CMQH7 zltkY@2e#^+8@o$aYY}*{GKMq$@8g0u-rfawjwFBl+0i>5$uN4}g%xR2tF_PzYF$QK zu!B+xF8rPFwj+l%*tNmF)TV~4RqC6n1 ziCF|kZuIFU5e`v%M<@I5!R{Ui<^%wfa~uFo{_G z!vE%i*D)va{)^vY*@l}HioB-jMC@_uB#ZR(ss~s&0ns_)d!I$w8I>pA6qKp|0N=7J zJlz~_zcVb@`3Bf3Dsg%nLz%<|y-}$bzg0t2;xO?G@l4Xv{?WKnVACRD>6p{;B5>2G zh&Pe)Y3X*zUK~e`9B>fM)2?=(g)sV8soE*J<tI3{xUUc z>QMEw1i&RTcGrkghC&&M)k-;DWkR6|F9%2Cs=QOZCBL01@ZP;Z#cs@UUU2rm0ThGo zP-^9&<-_!Qo@^CjpY)Blt*#xcZ$<^`d?3}Ci#ji=*j2o|#G1`@FPaZgz-NeyS2i?e zccNB!z^$H^R7AB%U~L?^&L%}*qBswG9eT!D`TLb^)RpQ07{)#~zL#I5BTvw@JzQ6w zhJ4%Kj2Un)KIk9DEygl6(O%L@2?6433vv0>15oQ*3YVPOG$DL`wuPkkU-_e7XQJ`E z;SCh8h&&q*`0Ytu#uWY-7Z1&c$Lnu}CTlhCz)`p#4$f3DOc61odffv$!x@slp>NWK zdX52XEP-3l0zl8_PFQ~eCR^}+ha7XIJ7M#VrJGM27UaaUaS8&*YTqy-z>^l>o5vxM zRnw$j+fw|Yc_%xncJrS#(>W&oSD^Q!UupJz9^K>x*3Ubb6qA;V04fG)Q;}%nOh@a@ce8QZlcy zc3|xfJb^L1Twfc#`r8ncFbveugS6)S6?qnH9!zm2oX$3cHvKxR8!vioMA6xAO2m}I z_3Wg0skWXwC9dUKU4$yVtDAEb_Aj*m8Q|T-87^9I6DLU(x8O{zwC<&RsA`>F0Y%u} z#j~rKzLEnkWp6JciYs)Usr|i7uOIlpvXwo}igq;sEVfUpx|+Ay<1mK)p8X%;+OMtq zY8!<}0ne4Q9@=-+lK!8E&z`s3A}58xf`0z;f7C>jHPQwg4Rj%* z(SosTOk|YLYta%go>U}>4?2;e-~5j#df00hKObENO4&lFLmu=SK;TYm^55xhcv?G$ zy$p?fwDc>qYo|1|oe}mkFtQZ^4`+epWEBebld7J0)6fqMXa6()kKT zKnkxSiT@+j!gV`SU5{t~$K-Pf+TKbTo$NW=M9CXY{vtwSI}VO94ilNBYzt zoa8keqkQ02N$w71ibs_aE_F7P=ZtD}UuD)UW^PI#_Dc6Fy^o7JRHRn1i2Y?r5kPzs zyY{hIqtoc-A)ierVHVhx|h zri`g_ZIJ!Esm!Sux)4K2I(cn(fUkTDCo$gXm`Zl{0b64w@2h9W-LQM6=C<7y-doKFLUA%~4>`rc(HkX`vk@3T%C4^qVP3`SEB z{mJ_@#WNSWL~F%YgAWaxS^w^8(zf*^-9UX(YV@L&;jd1%!n5lu%R67cs;dZHAde8X zK%N>tivdF56Zo@^D=&7eJ+;DB)El)beYC=r1^DANlF09cPcNW9V;^#g}@|W z!3eiwiUr1U=P52IQH`VY)P@Yw*X_gIX)gPPk1{%6ZM0+dVieVL!ih{Bn;j}1^p{@0 zX;JN1{N|?Y`f+xux{zEM7r3lHG~=@fzY)1eX#W2?*p!j(FKXfzl?@+XW>BnOiuh^M zoT@s)jXjOL>)FkYj*>mqGP<3fSDcH#g0Zrl{C&AL<=VY~inebUWDzlqRL!rPkK!-s zmbh2c?DNu23oyuh_(>?<3bC;@6J7WQrD^JZ*o!u;b>fwjZ@NeGzPA%m-kq_c95&7_ zX)m3>@Ju>mSYQVt`1&eXvQK27!M+e++G_S;_kGi#zOAs+w+ETE6k}5F(%sh5UYgm9Ii_HAh$ZwG7|fXXto|C`Yu=Z+)AWE;^_rB<@G#cW zyx}6GuPp`8EKF8_@Ro*6$3EH-RTx8<1H(x@{OoMmlCC?WC*I(K+VNShFvA_ z#44N8Y+P!qKw&QTx>wlZ{GiVhQR&zuLPNzB%LqC@$E2~k<&HGucty&Z4J{7t^>6K{ zG4=Pf@7Ux+ho0(OAr31hj}>wMS2%5X{NU&*m;A2$@^kdxnowu=3u`v?#^r;O1zt%@ zHUrJRqvp1#C`kyHbpmo*QaV+q5mhOHJ{% zzs}7>*N=v3gfyfj(9G408bY8x?)F6nS8y z>t+|<->ZS)K*nn>{o9k(RTpHlNvqHP zuJ{{D#@b&cKXmS~G~W!3w+365J1q)aKO{yhQ-FfufQh<4!}iN?Mrb9xt;6aZ`z$Xn zVAhop+8K3~yjNX1*&%@-r~@1n1ud5I-%pT<;!i+eNst~DhNSz_4h&Kxr%U*v*Nhg? zjl!8N)C$odMZBu%a$m(3R-zDRCuCqrk}F`g>3>+AdjF$Yj*=|?imJn_7O7!?j8=N` zgNbtsav%9yqO2*)wdL;@Z^MB2v8vAX*c=n|Th}G>ypE1DG-_$LhzbG&t7;>RX&n~3 zr(ZLOi2v~kb&wAaT`qO**_s1EVA6$xZF`T@vbM^c-@&|8vBlvL3QPRlylwtMbN~tC zAB|4~;ydT{3mF@p0@RUT^>1H*8rTKb9!CgqufH4#AkK2f364d=fX9D!{|=2_9yv$e z-c)s`Pd2G>L$@9&6E4pB1#?lyQijJk6&w2 Sh@|Ye~|0>}wMPLT8jm@Y!H33Sz}5aFI6 zM9Lzqz|;A*0sGs=2A1uU!1nk2dGF7knQwr99SAFen)x(eCO;F8y2C~0FD1YxRTPcy zPWVxkUYmeuz}Tv?7&Fe-!UE{)ZW)Mb;H)^#eHDv$`dkZGguJz@^MA!ZNGAUqt{|0H zpZ7Ch9S`q5!>R%}>}62!+(T^evyO+ImSo2wpu)su4^3nw5(%)KD%gbSev^*HZZ&3( z#&c@Z0gH|}Ck)w6fh0&NBJ62ib%R}(3@$VFl*_#l2W$wQ-~4RmZZAt5O*^2Q5}Xr8Hy@c`#pM?kc?hFWxRXr*mUfUCXf4ka5DD~ zat6d85COB05l#(P9*cQZ3EC8fVdS~?&vN#rce(aF9@xp80O2{{FBvU+{X>Hoh;xI` z{$e^Nw1y*VbO8wv`8|-m?NwNaKGTGaF{P^JLB^DbOYWIbn%eT`*!^C1H36=O8Z-M> zkD~88ry`eSo`tEBN4>w7OWZwUzlh{WM1m8R6zepqGcGMaV7vWY9b?K4b6~|HVG)ec wi>I@ws#sZo7or4_*4M>7;p5{nr2pZ?Uu4>Krr0kU)&Kwi07*qoM6N<$f)&@lf&c&j diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square107x107Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square107x107Logo.png deleted file mode 100644 index 0ca4f27198838968bd60ed7d371bfa23496b7fe5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2863 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 Y2S8W#vM)6=T>t<807*qoM6N<$f*y@n<^TWy diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square284x284Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square284x284Logo.png deleted file mode 100644 index c021d2ba76619c08969ab688db3b27f29257aa6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7737 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 diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square30x30Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square30x30Logo.png deleted file mode 100644 index 621970023096ed9f494ba18ace15421a45cd65fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 903 zcmV;219<$2P)2 z+CUKPMqaqGiH;zb!R4$B-WXS^YzQr=@UH>k4?*L)&R=zYjBrZenKdc9|JlS$SO*RJ zKt8FSTDAdk1g_WPAO!p^V!AuL;Lm;uQyV;zKq)J3i(;q*;k+pD%f3eltU`PYdy9(k0&%` zuWAPcV6|-y?|?7O1W!KSK}pbk8#~!|FA@(VJkt^V@0lio{afoAeo*f&$W2s6${5!1eKvAGD2$GZwSB98L2ZVS- zKn8ENRkZ*sb!@QugOrQNK3(sy1v%J#m|rpB+h|Nkqa3FRT>74xSs{#&saU2Lf!_Iq zKmuKAESh`gs!fneGWn+nf}l?7jE$HW!Af&vE5=G!QU)U2v&HLIBGXKk4nQx{hsHjL zLPMAo5=*uInFbq7(aa`Y2VX5wCmaeqvECOFv)a>0t>ZaEb*cJccER=BB?KFZhV$c^ znL*l8x*UYZv4WK|j?~Jt6~~F%{pk~z5A*>^M`?r5m9@RJ_x|uEtX(6Vk@Y()MVto* z93wr)%3m%|#OZ~srm>zF(JvDuTq*@;d&^>_BJm5hOU`3FjG70L#Vzv9I?`<7$T@

jU?lMi@tgxr7CqX_r3uw^y4tVU3Pm0sw;|1WSUO%?=bG`*Kmz6u4{#ti;T7AWIBAEh!(Y zz>O01&#X?Ds@L)Sb{CkG#Yz4$3o d@96)?#cz^xWoA}>B$xmI002ovPDHLkV1l3&k#zt7 diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square310x310Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square310x310Logo.png deleted file mode 100644 index f9bc04839491e66c07b16ab03743c0c53b4109cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8591 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 JPDHLkV1lm|RXG3v diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square71x71Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square71x71Logo.png deleted file mode 100644 index 63440d7984936a9caa89275928d8dce97e4d033b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2011 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∓t$dRJGIadE?vc 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 Kx8Vjl{{H|h@<;Lj diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/icon.ico b/examples/tauri/github-oauth/app/src-tauri/icons/icon.ico deleted file mode 100644 index b3636e4b22ba65db9061cd60a77b02c92022dfd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86642 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 AKmY&$ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/icon.png b/examples/tauri/github-oauth/app/src-tauri/icons/icon.png deleted file mode 100644 index e1cd2619e0b5ec089cbba5ec7b03ddf2b1dfceb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14183 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

5l#v3A#xI3*z~1~fvo9Q(N^(==!|_FZ z*duZ=+M1~)8E|otX8KNZlr?qels#x_1Xq@9IIw~@9uAREJVH)Xw^}UclF6327}E42 zT)E&?U%TK?(+K7%R!`H5oX0i)4Qn5??Iw3p5J~6_u+aWehY{DSn}3V2p$bgjnAu?o)v@iC254fXeMv50$9YrpU`N?u@QIWs)T?SP|fa}(|9 zqAX+!7`cx=4)cCBg5h~pu(?@9`)aCr#oyz$ld=#RFxYCNZCZls@4v2~*e-t6PEVvV z&bbK3b3wt(Coc!ufAbXXC<**#HQ%J9k`New6iG<5RjtO4XVO?dCvwxD{kJ#tfQr(X zg^NTwF-FwAeS_{V4bfel8l`~NbfrTR2s!G>WduFWxH(t~aK4q=6rEE^$+Uox>gJO2 z{L<;6Q6nHa5#ZEM>H58not!)z(6*_=^~8}jWf*IG$AUKVWOZ4?)GfF z+BM#*wKKmLFD7E~W3U!$IVm$k_k1f&Kz6WV8@55P?r~bcg-Za-!rvW?ns&)KOGT2~ zlkAyqhQj=P$Eg3w#K~}zH@J5bo-BfHjInKSz$@?+Z)NPD4pHj^_Qxmi`UqoTy=`sV zLVxrXGuBr=QRm|}wg75yetQQK4fY3#P_~J}zEfPnb2C4Wo!E(d*(cA;b?7$g2in<( zPn)ghX}nzJPmb6(3Dpeg_GW~Hc}Lt=lgsSZz z!5QXyz7KaR;D`3Ee}d`af{H>WWZ|Io1QI3~4Ll_`g1(cRnhLK73Ro)7zPCd={1W2x zRp%Xlvv4>!<2@}$hz|!V{T}_eHx2xkLl^hQoZTCnsjCl|W_@5Fx2(+j0ogy&Y+;L- z<)G$*CiN7hOm^s!{U>1F7U=iNk{+u~dAC!eDz%=|glFW0jEZU1&o(G_c#wTxUjnG} z#cg3>jEpUi#Mlq@t?Msg_#geK^Lx@DyHWf7=AS5vVyM7YOjvUVCfcpVR<(+5!H?9- zySI6s>o3m&*zr||=wcPGyBkQV`EWJl@bH8qobjOp+sXL*)=&yX)8aAbf~tGv?a2SN zu^Ddo-z?DWk9h9Yz#5p^NU#x~wYSd?H@w@!2Gb4G)6-utEMV~~M85Br5ff(v5O1|T z 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 Result { - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let port = listener.local_addr().unwrap().port(); - shell::open( - &app_handle.shell_scope(), - format!("http://localhost:3000/login/github?port={}", port), - None, - ) - .unwrap(); - let (mut stream, _) = listener.accept().await.unwrap(); - let (reader, writer) = stream.split(); - let mut buf_reader = BufReader::new(reader); - let mut buf = String::new(); - // the pathname is the 2nd item in the first line - buf_reader.read_line(&mut buf).await.unwrap(); - let url = buf.split_ascii_whitespace().nth(1).unwrap(); - let (_, query) = url.split_once('?').unwrap_or_default(); - for query_pair in query.split('&') { - if let Some(("session_token", value)) = query_pair.split_once('=') { - writer - .try_write( - b"HTTP/1.1 200 OK\r\n\r\nSuccessfully logged in. You can now close this tab.", - ) - .unwrap(); - return Ok(value.to_string()); - } - } - Err("Missing session".to_string()) -} - -fn main() { - tauri::Builder::default() - .invoke_handler(tauri::generate_handler![authenticate]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} diff --git a/examples/tauri/github-oauth/app/src-tauri/tauri.conf.json b/examples/tauri/github-oauth/app/src-tauri/tauri.conf.json deleted file mode 100644 index c679f226f..000000000 --- a/examples/tauri/github-oauth/app/src-tauri/tauri.conf.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "build": { - "beforeDevCommand": "pnpm dev", - "beforeBuildCommand": "pnpm build", - "devPath": "http://localhost:1420", - "distDir": "../dist", - "withGlobalTauri": true - }, - "package": { - "productName": "app", - "version": "0.0.0" - }, - "tauri": { - "allowlist": { - "shell": { - "open": true - }, - "http": { - "request": true, - "scope": [" http://localhost:3000/*"] - } - }, - "bundle": { - "active": true, - "targets": "all", - "identifier": "com.tauri.dev", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ] - }, - "security": { - "csp": null - }, - "windows": [ - { - "fullscreen": false, - "resizable": true, - "title": "app", - "width": 800, - "height": 600 - } - ] - } -} diff --git a/examples/tauri/github-oauth/app/src/main.ts b/examples/tauri/github-oauth/app/src/main.ts deleted file mode 100644 index 105e20fff..000000000 --- a/examples/tauri/github-oauth/app/src/main.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { invoke } from "@tauri-apps/api/tauri"; -import { getClient, ResponseType } from "@tauri-apps/api/http"; - -window.addEventListener("DOMContentLoaded", async () => { - const loginButton = document.getElementById("login-button"); - const profileBody = document.getElementById("profile"); - const logoutButton = document.getElementById("logout-button"); - if (!loginButton || !profileBody || !logoutButton) return; - - const renderUserProfile = (user: User | null) => { - profileBody.textContent = user ? JSON.stringify(user, null, 2) : "(none)"; - }; - - loginButton.addEventListener("click", async () => { - try { - const sessionToken = await invoke("authenticate"); - localStorage.setItem("session_token", sessionToken); - const user = await getUser(sessionToken); - renderUserProfile(user); - } catch (e) { - console.log(e); - } - }); - logoutButton.addEventListener("click", async () => { - const sessionToken = localStorage.getItem("session_token"); - if (!sessionToken) return; - const client = await getClient(); - const response = await client.request({ - url: "http://localhost:3000/logout", - method: "POST", - headers: { - Authorization: `Bearer ${sessionToken}` - } - }); - if (!response.ok) return; - localStorage.removeItem("session_token"); - renderUserProfile(null); - }); - - const sessionToken = localStorage.getItem("session_token"); - if (sessionToken) { - const user = await getUser(sessionToken); - if (!user) { - localStorage.removeItem("session_token"); - } - renderUserProfile(user); - } -}); - -const getUser = async (sessionToken: string): Promise => { - const client = await getClient(); - const response = await client.get("http://localhost:3000/user", { - headers: { - Authorization: `Bearer ${sessionToken}` - }, - responseType: ResponseType.JSON - }); - if (!response.ok) { - return null; - } - return response.data; -}; - -type User = { - userId: string; - username: string; -}; diff --git a/examples/tauri/github-oauth/app/src/styles.css b/examples/tauri/github-oauth/app/src/styles.css deleted file mode 100644 index 4afb4dde1..000000000 --- a/examples/tauri/github-oauth/app/src/styles.css +++ /dev/null @@ -1,7 +0,0 @@ -body { - padding: 2rem; -} -* { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} diff --git a/examples/tauri/github-oauth/app/tsconfig.json b/examples/tauri/github-oauth/app/tsconfig.json deleted file mode 100644 index e33806465..000000000 --- a/examples/tauri/github-oauth/app/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/examples/tauri/github-oauth/app/vite.config.ts b/examples/tauri/github-oauth/app/vite.config.ts deleted file mode 100644 index b2a39b806..000000000 --- a/examples/tauri/github-oauth/app/vite.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineConfig } from "vite"; - -// https://vitejs.dev/config/ -export default defineConfig(async () => ({ - // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` - // - // 1. prevent vite from obscuring rust errors - clearScreen: false, - // 2. tauri expects a fixed port, fail if that port is not available - server: { - port: 1420, - strictPort: true - }, - // 3. to make use of `TAURI_DEBUG` and other env variables - // https://tauri.studio/v1/api/config#buildconfig.beforedevcommand - envPrefix: ["VITE_", "TAURI_"] -})); diff --git a/examples/tauri/github-oauth/server/.env.example b/examples/tauri/github-oauth/server/.env.example deleted file mode 100644 index 0e0e5f95b..000000000 --- a/examples/tauri/github-oauth/server/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -GITHUB_CLIENT_ID="" -GITHUB_CLIENT_SECRET="" \ No newline at end of file diff --git a/examples/tauri/github-oauth/server/.gitignore b/examples/tauri/github-oauth/server/.gitignore deleted file mode 100644 index 1dcef2d9f..000000000 --- a/examples/tauri/github-oauth/server/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.env \ No newline at end of file diff --git a/examples/tauri/github-oauth/server/package.json b/examples/tauri/github-oauth/server/package.json deleted file mode 100644 index c7b261fbc..000000000 --- a/examples/tauri/github-oauth/server/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scripts": { - "start": "tsx src/index.ts" - }, - "dependencies": { - "@hono/node-server": "^1.1.0", - "@lucia-auth/adapter-sqlite": "latest", - "@lucia-auth/oauth": "latest", - "better-sqlite3": "^8.4.0", - "dotenv": "^16.0.3", - "hono": "^3.6.0", - "lucia": "latest" - }, - "devDependencies": { - "@types/better-sqlite3": "^7.6.3", - "tsx": "^3.12.2" - } -} diff --git a/examples/tauri/github-oauth/server/src/app.d.ts b/examples/tauri/github-oauth/server/src/app.d.ts deleted file mode 100644 index 343cbac48..000000000 --- a/examples/tauri/github-oauth/server/src/app.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// -declare namespace Lucia { - type Auth = import("./auth").Auth; - type DatabaseUserAttributes = { - username: string; - }; - type DatabaseSessionAttributes = {}; -} diff --git a/examples/tauri/github-oauth/server/src/auth.ts b/examples/tauri/github-oauth/server/src/auth.ts deleted file mode 100644 index b8696b16d..000000000 --- a/examples/tauri/github-oauth/server/src/auth.ts +++ /dev/null @@ -1,37 +0,0 @@ -import dotenv from "dotenv"; - -dotenv.config(); - -import { lucia } from "lucia"; -import { hono } from "lucia/middleware"; -import { betterSqlite3 } from "@lucia-auth/adapter-sqlite"; - -import { github } from "@lucia-auth/oauth/providers"; - -import sqlite from "better-sqlite3"; -import fs from "fs"; - -const db = sqlite(":memory:"); -db.exec(fs.readFileSync("src/schema.sql", "utf8")); - -export const auth = lucia({ - env: process.env.NODE_ENV === "production" ? "PROD" : "DEV", - adapter: betterSqlite3(db, { - user: "user", - session: "user_session", - key: "user_key" - }), - middleware: hono(), - getUserAttributes: (data) => { - return { - username: data.username - }; - } -}); - -export type Auth = typeof auth; - -export const githubAuth = github(auth, { - clientId: process.env.GITHUB_CLIENT_ID ?? "", - clientSecret: process.env.GITHUB_CLIENT_SECRET ?? "" -}); diff --git a/examples/tauri/github-oauth/server/src/index.ts b/examples/tauri/github-oauth/server/src/index.ts deleted file mode 100644 index 4ec98545c..000000000 --- a/examples/tauri/github-oauth/server/src/index.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { serve } from "@hono/node-server"; -import { Hono } from "hono"; -import { getCookie, setCookie } from "hono/cookie"; -import { auth, githubAuth } from "./auth"; -import { OAuthRequestError } from "@lucia-auth/oauth"; - -const app = new Hono(); - -app.get("/user", async (c) => { - const authRequest = auth.handleRequest(c); - const session = await authRequest.validateBearerToken(); - if (!session) { - return c.newResponse(null, 401); - } - return c.json(session.user); -}); - -app.get("/login/github", async (c) => { - const url = new URL(c.req.url); - const port = url.searchParams.get("port"); - if (!port) return c.newResponse(null, 400); - const [authorizationUrl, state] = await githubAuth.getAuthorizationUrl(); - setCookie(c, "github_oauth_state", state, { - path: "/", - maxAge: 60 * 10, - httpOnly: true, - secure: process.env.NODE_ENV === "production" - }); - setCookie(c, "redirect_port", port, { - path: "/", - maxAge: 60 * 10, - httpOnly: true, - secure: process.env.NODE_ENV === "production" - }); - return c.redirect(authorizationUrl.toString()); -}); - -app.get("/login/github/callback", async (c) => { - const url = new URL(c.req.url); - const code = url.searchParams.get("code"); - if (!code) return c.newResponse(null, 400); - const state = url.searchParams.get("state"); - const storedState = getCookie(c, "github_oauth_state"); - if (!state || !storedState || state !== storedState) { - return c.newResponse(null, 400); - } - const redirectPort = getCookie(c, "redirect_port"); - if (!redirectPort) return c.newResponse(null, 400); - try { - const { getExistingUser, githubUser, createUser } = - await githubAuth.validateCallback(code); - let user = await getExistingUser(); - if (!user) { - user = await createUser({ - attributes: { - username: githubUser.login - } - }); - } - const session = await auth.createSession({ - userId: user.userId, - attributes: {} - }); - return c.redirect( - `http://localhost:${redirectPort}?session_token=${session.sessionId}` - ); - } catch (e) { - console.log(e); - if (e instanceof OAuthRequestError) { - // invalid code - return c.newResponse(null, 400); - } - return c.newResponse(null, 500); - } -}); - -app.post("/logout", async (c) => { - const authRequest = auth.handleRequest(c); - const session = await authRequest.validateBearerToken(); - if (!session) return c.newResponse(null, 401); - await auth.invalidateSession(session.sessionId); - return c.newResponse(null, 200); -}); - -serve(app); diff --git a/examples/tauri/github-oauth/server/src/schema.sql b/examples/tauri/github-oauth/server/src/schema.sql deleted file mode 100644 index 013ddfbc3..000000000 --- a/examples/tauri/github-oauth/server/src/schema.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE user ( - id VARCHAR(15) PRIMARY KEY, - username VARCHAR(31) NOT NULL -); -CREATE TABLE user_key ( - id VARCHAR(255) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - hashed_password VARCHAR(255), - FOREIGN KEY (user_id) REFERENCES user(id) -); -CREATE TABLE user_session ( - id VARCHAR(127) PRIMARY KEY, - user_id VARCHAR(15) NOT NULL, - active_expires BIGINT NOT NULL, - idle_expires BIGINT NOT NULL, - FOREIGN KEY (user_id) REFERENCES user(id) -); \ No newline at end of file diff --git a/package.json b/package.json index cedf2f6c9..77f4ff315 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "version": "1.0.0", "description": "Authentication, simple and clean", "scripts": { - "ready": "pnpm i && cd packages/lucia && pnpm build && cd ../adapter-test && pnpm build && cd ../oauth && pnpm build && cd ../adapter-sqlite && pnpm build && cd ../../", "publish-setup": "pnpm i --no-frozen-lockfile && cd packages/lucia && pnpm build && cd ../adapter-test && pnpm build && cd ../../", "format": "pnpm exec prettier --write . --plugin=prettier-plugin-astro", "format:docs": "pnpm exec prettier --write documentation --plugin=prettier-plugin-astro", diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1b61cb92b..541d78ad3 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,3 @@ packages: - "packages/*" - "documentation/**" - - "examples/**"