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 fb282da07..000000000 Binary files a/examples/solidstart/github-oauth/public/favicon.ico and /dev/null differ diff --git a/examples/solidstart/github-oauth/schema.sql b/examples/solidstart/github-oauth/schema.sql deleted file mode 100644 index c62ad0cfb..000000000 --- a/examples/solidstart/github-oauth/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/solidstart/github-oauth/src/app.d.ts b/examples/solidstart/github-oauth/src/app.d.ts deleted file mode 100644 index 8a2c49f17..000000000 --- a/examples/solidstart/github-oauth/src/app.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// -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 fb282da07..000000000 Binary files a/examples/solidstart/username-and-password/public/favicon.ico and /dev/null differ diff --git a/examples/solidstart/username-and-password/schema.sql b/examples/solidstart/username-and-password/schema.sql deleted file mode 100644 index c62ad0cfb..000000000 --- a/examples/solidstart/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/solidstart/username-and-password/src/app.d.ts b/examples/solidstart/username-and-password/src/app.d.ts deleted file mode 100644 index 8a2c49f17..000000000 --- a/examples/solidstart/username-and-password/src/app.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// -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 825b9e65a..000000000 Binary files a/examples/sveltekit/email-and-password/static/favicon.png and /dev/null differ diff --git a/examples/sveltekit/email-and-password/svelte.config.js b/examples/sveltekit/email-and-password/svelte.config.js deleted file mode 100644 index 1cf26a00d..000000000 --- a/examples/sveltekit/email-and-password/svelte.config.js +++ /dev/null @@ -1,18 +0,0 @@ -import adapter from '@sveltejs/adapter-auto'; -import { vitePreprocess } from '@sveltejs/kit/vite'; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - // Consult https://kit.svelte.dev/docs/integrations#preprocessors - // for more information about preprocessors - preprocess: vitePreprocess(), - - kit: { - // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. - // If your environment is not supported or you settled on a specific environment, switch out the adapter. - // See https://kit.svelte.dev/docs/adapters for more information about adapters. - adapter: adapter() - } -}; - -export default config; diff --git a/examples/sveltekit/email-and-password/tsconfig.json b/examples/sveltekit/email-and-password/tsconfig.json deleted file mode 100644 index 6ae0c8c44..000000000 --- a/examples/sveltekit/email-and-password/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true - } - // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias - // - // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes - // from the referenced tsconfig.json - TypeScript does not merge them in -} diff --git a/examples/sveltekit/email-and-password/vite.config.ts b/examples/sveltekit/email-and-password/vite.config.ts deleted file mode 100644 index bbf8c7da4..000000000 --- a/examples/sveltekit/email-and-password/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; - -export default defineConfig({ - plugins: [sveltekit()] -}); diff --git a/examples/sveltekit/github-oauth/.env.example b/examples/sveltekit/github-oauth/.env.example deleted file mode 100644 index 0e0e5f95b..000000000 --- a/examples/sveltekit/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/sveltekit/github-oauth/.eslintignore b/examples/sveltekit/github-oauth/.eslintignore deleted file mode 100644 index 38972655f..000000000 --- a/examples/sveltekit/github-oauth/.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/github-oauth/.eslintrc.cjs b/examples/sveltekit/github-oauth/.eslintrc.cjs deleted file mode 100644 index ebc19589f..000000000 --- a/examples/sveltekit/github-oauth/.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/github-oauth/.gitignore b/examples/sveltekit/github-oauth/.gitignore deleted file mode 100644 index 07442e394..000000000 --- a/examples/sveltekit/github-oauth/.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/github-oauth/.npmrc b/examples/sveltekit/github-oauth/.npmrc deleted file mode 100644 index 0c05da457..000000000 --- a/examples/sveltekit/github-oauth/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -engine-strict=true -resolution-mode=highest diff --git a/examples/sveltekit/github-oauth/.prettierignore b/examples/sveltekit/github-oauth/.prettierignore deleted file mode 100644 index 38972655f..000000000 --- a/examples/sveltekit/github-oauth/.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/github-oauth/.prettierrc b/examples/sveltekit/github-oauth/.prettierrc deleted file mode 100644 index a77fddea9..000000000 --- a/examples/sveltekit/github-oauth/.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/github-oauth/README.md b/examples/sveltekit/github-oauth/README.md deleted file mode 100644 index 53f07f643..000000000 --- a/examples/sveltekit/github-oauth/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# GitHub OAuth example with Lucia and SvelteKit - -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/sveltekit/github-oauth/package.json b/examples/sveltekit/github-oauth/package.json deleted file mode 100644 index 3e3558f61..000000000 --- a/examples/sveltekit/github-oauth/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "github-oauth", - "description": "GitHub OAuth 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", - "@lucia-auth/oauth": "latest", - "better-sqlite3": "^8.4.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/github-oauth/schema.sql b/examples/sveltekit/github-oauth/schema.sql deleted file mode 100644 index 013ddfbc3..000000000 --- a/examples/sveltekit/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/sveltekit/github-oauth/src/app.css b/examples/sveltekit/github-oauth/src/app.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/sveltekit/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/sveltekit/github-oauth/src/app.d.ts b/examples/sveltekit/github-oauth/src/app.d.ts deleted file mode 100644 index fc4f47ea1..000000000 --- a/examples/sveltekit/github-oauth/src/app.d.ts +++ /dev/null @@ -1,22 +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 = { - 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 825b9e65a..000000000 Binary files a/examples/sveltekit/github-oauth/static/favicon.png and /dev/null differ diff --git a/examples/sveltekit/github-oauth/svelte.config.js b/examples/sveltekit/github-oauth/svelte.config.js deleted file mode 100644 index 1cf26a00d..000000000 --- a/examples/sveltekit/github-oauth/svelte.config.js +++ /dev/null @@ -1,18 +0,0 @@ -import adapter from '@sveltejs/adapter-auto'; -import { vitePreprocess } from '@sveltejs/kit/vite'; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - // Consult https://kit.svelte.dev/docs/integrations#preprocessors - // for more information about preprocessors - preprocess: vitePreprocess(), - - kit: { - // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. - // If your environment is not supported or you settled on a specific environment, switch out the adapter. - // See https://kit.svelte.dev/docs/adapters for more information about adapters. - adapter: adapter() - } -}; - -export default config; diff --git a/examples/sveltekit/github-oauth/tsconfig.json b/examples/sveltekit/github-oauth/tsconfig.json deleted file mode 100644 index 6ae0c8c44..000000000 --- a/examples/sveltekit/github-oauth/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true - } - // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias - // - // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes - // from the referenced tsconfig.json - TypeScript does not merge them in -} diff --git a/examples/sveltekit/github-oauth/vite.config.ts b/examples/sveltekit/github-oauth/vite.config.ts deleted file mode 100644 index bbf8c7da4..000000000 --- a/examples/sveltekit/github-oauth/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; - -export default defineConfig({ - plugins: [sveltekit()] -}); diff --git a/examples/sveltekit/username-and-password/.eslintignore b/examples/sveltekit/username-and-password/.eslintignore deleted file mode 100644 index 38972655f..000000000 --- a/examples/sveltekit/username-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/username-and-password/.eslintrc.cjs b/examples/sveltekit/username-and-password/.eslintrc.cjs deleted file mode 100644 index ebc19589f..000000000 --- a/examples/sveltekit/username-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/username-and-password/.gitignore b/examples/sveltekit/username-and-password/.gitignore deleted file mode 100644 index 07442e394..000000000 --- a/examples/sveltekit/username-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/username-and-password/.npmrc b/examples/sveltekit/username-and-password/.npmrc deleted file mode 100644 index 0c05da457..000000000 --- a/examples/sveltekit/username-and-password/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -engine-strict=true -resolution-mode=highest diff --git a/examples/sveltekit/username-and-password/.prettierignore b/examples/sveltekit/username-and-password/.prettierignore deleted file mode 100644 index 38972655f..000000000 --- a/examples/sveltekit/username-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/username-and-password/.prettierrc b/examples/sveltekit/username-and-password/.prettierrc deleted file mode 100644 index a77fddea9..000000000 --- a/examples/sveltekit/username-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/username-and-password/README.md b/examples/sveltekit/username-and-password/README.md deleted file mode 100644 index bc6ebc237..000000000 --- a/examples/sveltekit/username-and-password/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Username & 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` | | -| `username` | `string` | ✓ | diff --git a/examples/sveltekit/username-and-password/package.json b/examples/sveltekit/username-and-password/package.json deleted file mode 100644 index dbe3817ec..000000000 --- a/examples/sveltekit/username-and-password/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "username-and-password", - "description": "Username & 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", - "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/username-and-password/schema.sql b/examples/sveltekit/username-and-password/schema.sql deleted file mode 100644 index c62ad0cfb..000000000 --- a/examples/sveltekit/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/sveltekit/username-and-password/src/app.css b/examples/sveltekit/username-and-password/src/app.css deleted file mode 100644 index 1b3aad536..000000000 --- a/examples/sveltekit/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/sveltekit/username-and-password/src/app.d.ts b/examples/sveltekit/username-and-password/src/app.d.ts deleted file mode 100644 index fc4f47ea1..000000000 --- a/examples/sveltekit/username-and-password/src/app.d.ts +++ /dev/null @@ -1,22 +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 = { - 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 825b9e65a..000000000 Binary files a/examples/sveltekit/username-and-password/static/favicon.png and /dev/null differ diff --git a/examples/sveltekit/username-and-password/svelte.config.js b/examples/sveltekit/username-and-password/svelte.config.js deleted file mode 100644 index 1cf26a00d..000000000 --- a/examples/sveltekit/username-and-password/svelte.config.js +++ /dev/null @@ -1,18 +0,0 @@ -import adapter from '@sveltejs/adapter-auto'; -import { vitePreprocess } from '@sveltejs/kit/vite'; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - // Consult https://kit.svelte.dev/docs/integrations#preprocessors - // for more information about preprocessors - preprocess: vitePreprocess(), - - kit: { - // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. - // If your environment is not supported or you settled on a specific environment, switch out the adapter. - // See https://kit.svelte.dev/docs/adapters for more information about adapters. - adapter: adapter() - } -}; - -export default config; diff --git a/examples/sveltekit/username-and-password/tsconfig.json b/examples/sveltekit/username-and-password/tsconfig.json deleted file mode 100644 index 6ae0c8c44..000000000 --- a/examples/sveltekit/username-and-password/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true - } - // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias - // - // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes - // from the referenced tsconfig.json - TypeScript does not merge them in -} diff --git a/examples/sveltekit/username-and-password/vite.config.ts b/examples/sveltekit/username-and-password/vite.config.ts deleted file mode 100644 index bbf8c7da4..000000000 --- a/examples/sveltekit/username-and-password/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; - -export default defineConfig({ - plugins: [sveltekit()] -}); diff --git a/examples/tauri/github-oauth/README.md b/examples/tauri/github-oauth/README.md deleted file mode 100644 index 363305bd5..000000000 --- a/examples/tauri/github-oauth/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# GitHub OAuth example with Lucia and Tauri - -This example has 2 parts: the Tauri application and the TS server with Lucia. Uses SQLite3 with `better-sqlite3` as the database. - -## App - -Inside `app` directory. - -```bash -# install dependencies -pnpm i - -# run dev server -pnpm tauri dev -``` - -## 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/tauri/github-oauth/app/.gitignore b/examples/tauri/github-oauth/app/.gitignore deleted file mode 100644 index a547bf36d..000000000 --- a/examples/tauri/github-oauth/app/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/examples/tauri/github-oauth/app/index.html b/examples/tauri/github-oauth/app/index.html deleted file mode 100644 index b5de1edde..000000000 --- a/examples/tauri/github-oauth/app/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - 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 6be5e50e9..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/128x128.png and /dev/null differ 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 e81becee5..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/128x128@2x.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/32x32.png b/examples/tauri/github-oauth/app/src-tauri/icons/32x32.png deleted file mode 100644 index a437dd517..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/32x32.png and /dev/null differ 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 0ca4f2719..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square107x107Logo.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square142x142Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square142x142Logo.png deleted file mode 100644 index b81f82039..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square142x142Logo.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square150x150Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square150x150Logo.png deleted file mode 100644 index 624c7bfba..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square150x150Logo.png and /dev/null differ 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 c021d2ba7..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square284x284Logo.png and /dev/null differ 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 621970023..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square30x30Logo.png and /dev/null differ 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 f9bc04839..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square310x310Logo.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square44x44Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square44x44Logo.png deleted file mode 100644 index d5fbfb2ab..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square44x44Logo.png and /dev/null differ 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 63440d798..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square71x71Logo.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/Square89x89Logo.png b/examples/tauri/github-oauth/app/src-tauri/icons/Square89x89Logo.png deleted file mode 100644 index f3f705af2..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/Square89x89Logo.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/StoreLogo.png b/examples/tauri/github-oauth/app/src-tauri/icons/StoreLogo.png deleted file mode 100644 index 455638826..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/StoreLogo.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/icons/icon.icns b/examples/tauri/github-oauth/app/src-tauri/icons/icon.icns deleted file mode 100644 index 12a5bcee2..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/icon.icns and /dev/null differ 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 b3636e4b2..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/icon.ico and /dev/null differ 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 e1cd2619e..000000000 Binary files a/examples/tauri/github-oauth/app/src-tauri/icons/icon.png and /dev/null differ diff --git a/examples/tauri/github-oauth/app/src-tauri/src/main.rs b/examples/tauri/github-oauth/app/src-tauri/src/main.rs deleted file mode 100644 index c43279aeb..000000000 --- a/examples/tauri/github-oauth/app/src-tauri/src/main.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -use tauri::api::shell; -use tauri::{AppHandle, Manager}; -use tokio::io::{AsyncBufReadExt, BufReader}; -use tokio::net::TcpListener; - -#[tauri::command] -async fn authenticate(app_handle: AppHandle) -> 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/**"