From 64df574591d9e3d3e53525c939a134d3b2f78411 Mon Sep 17 00:00:00 2001 From: pilcrow Date: Sun, 10 Mar 2024 13:00:25 +0900 Subject: [PATCH] Reference the Copenhagen Book in docs (#1479) --- docs/pages/getting-started/astro.md | 2 + docs/pages/getting-started/express.md | 2 + docs/pages/getting-started/index.md | 4 ++ docs/pages/getting-started/nextjs-app.md | 4 +- docs/pages/getting-started/nextjs-pages.md | 5 +- docs/pages/getting-started/nuxt.md | 2 + docs/pages/getting-started/solidstart.md | 2 + docs/pages/getting-started/sveltekit.md | 2 + .../email-verification-codes.md | 2 + .../email-verification-links.md | 11 +++- docs/pages/guides/email-and-password/index.md | 2 + .../email-and-password/password-reset.md | 51 ++++++++++++++----- docs/pages/guides/oauth/account-linking.md | 4 +- docs/pages/guides/oauth/index.md | 2 + docs/pages/guides/passkeys.md | 2 + 15 files changed, 79 insertions(+), 18 deletions(-) diff --git a/docs/pages/getting-started/astro.md b/docs/pages/getting-started/astro.md index 7af15b57e..3bdd4d60b 100644 --- a/docs/pages/getting-started/astro.md +++ b/docs/pages/getting-started/astro.md @@ -117,4 +117,6 @@ declare namespace App { You can learn all the concepts and APIs by reading the [Basics section](/basics/sessions) in the docs. If you prefer writing code immediately, check out the [Tutorials](/tutorials) page or the [examples repository](https://github.com/lucia-auth/examples/tree/main). +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. + If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! diff --git a/docs/pages/getting-started/express.md b/docs/pages/getting-started/express.md index 512d8f283..f3d815aa5 100644 --- a/docs/pages/getting-started/express.md +++ b/docs/pages/getting-started/express.md @@ -56,4 +56,6 @@ node --experimental-web-crypto index.js You can learn all the concepts and APIs by reading the [Basics section](/basics/sessions) in the docs. If you prefer writing code immediately, check out the [Tutorials](/tutorials) page or the [examples repository](https://github.com/lucia-auth/examples/tree/main). +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. + If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! diff --git a/docs/pages/getting-started/index.md b/docs/pages/getting-started/index.md index e1cb24afb..1f96259fe 100644 --- a/docs/pages/getting-started/index.md +++ b/docs/pages/getting-started/index.md @@ -89,3 +89,7 @@ module.exports = { externals: ["@node-rs/argon2", "@node-rs/bcrypt"] }; ``` + +## The Copenhagen Book + +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. \ No newline at end of file diff --git a/docs/pages/getting-started/nextjs-app.md b/docs/pages/getting-started/nextjs-app.md index 2b01cb1ba..51a89a810 100644 --- a/docs/pages/getting-started/nextjs-app.md +++ b/docs/pages/getting-started/nextjs-app.md @@ -82,4 +82,6 @@ Currently, `oslo/password` cannot be used with Turbopack. You can learn all the concepts and APIs by reading the [Basics section](/basics/sessions) in the docs. If you prefer writing code immediately, check out the [Tutorials](/tutorials) page or the [examples repository](https://github.com/lucia-auth/examples/tree/main). -If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. + +If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! \ No newline at end of file diff --git a/docs/pages/getting-started/nextjs-pages.md b/docs/pages/getting-started/nextjs-pages.md index 691d22880..e36ddcba8 100644 --- a/docs/pages/getting-started/nextjs-pages.md +++ b/docs/pages/getting-started/nextjs-pages.md @@ -82,4 +82,7 @@ export async function middleware(request: NextRequest): Promise { You can learn all the concepts and APIs by reading the [Basics section](/basics/sessions) in the docs. If you prefer writing code immediately, check out the [Tutorials](/tutorials) page or the [examples repository](https://github.com/lucia-auth/examples/tree/main). -If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. + + +If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! \ No newline at end of file diff --git a/docs/pages/getting-started/nuxt.md b/docs/pages/getting-started/nuxt.md index 7b5ae0312..134df38c2 100644 --- a/docs/pages/getting-started/nuxt.md +++ b/docs/pages/getting-started/nuxt.md @@ -112,4 +112,6 @@ declare module "h3" { You can learn all the concepts and APIs by reading the [Basics section](/basics/sessions) in the docs. If you prefer writing code immediately, check out the [Tutorials](/tutorials) page or the [examples repository](https://github.com/lucia-auth/examples/tree/main). +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. + If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! diff --git a/docs/pages/getting-started/solidstart.md b/docs/pages/getting-started/solidstart.md index 9ba59d33c..06d63ec68 100644 --- a/docs/pages/getting-started/solidstart.md +++ b/docs/pages/getting-started/solidstart.md @@ -105,4 +105,6 @@ export default defineConfig({ You can learn all the concepts and APIs by reading the [Basics section](/basics/sessions) in the docs. If you prefer writing code immediately, check out the [Tutorials](/tutorials) page or the [examples repository](https://github.com/lucia-auth/examples/tree/main). +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. + If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! diff --git a/docs/pages/getting-started/sveltekit.md b/docs/pages/getting-started/sveltekit.md index 61441d977..e0bd1bdbb 100644 --- a/docs/pages/getting-started/sveltekit.md +++ b/docs/pages/getting-started/sveltekit.md @@ -109,4 +109,6 @@ export {}; You can learn all the concepts and APIs by reading the [Basics section](/basics/sessions) in the docs. If you prefer writing code immediately, check out the [Tutorials](/tutorials) page or the [examples repository](https://github.com/lucia-auth/examples/tree/main). +This documentation often references [the Copenhagen Book](https://thecopenhagenbook.com/mfa). This is an open-source guide on implementing auth and should come in handy when implementing anything auth, including passkeys, multi-factor authentication, and a bit of cryptography. We recommend reading it to learn more about auth in web applications. + If you have any questions, [join our Discord server](https://discord.com/invite/PwrK3kpVR3)! diff --git a/docs/pages/guides/email-and-password/email-verification-codes.md b/docs/pages/guides/email-and-password/email-verification-codes.md index 7a9e809fa..a85ce92cf 100644 --- a/docs/pages/guides/email-and-password/email-verification-codes.md +++ b/docs/pages/guides/email-and-password/email-verification-codes.md @@ -4,6 +4,8 @@ title: "Email verification codes" # Email verification codes +We recommend reading through the [email verification guide](https://thecopenhagenbook.com/email-verification) in the Copenhagen Book. + ## Update database ### User table diff --git a/docs/pages/guides/email-and-password/email-verification-links.md b/docs/pages/guides/email-and-password/email-verification-links.md index 48530bb94..27c2d6f7b 100644 --- a/docs/pages/guides/email-and-password/email-verification-links.md +++ b/docs/pages/guides/email-and-password/email-verification-links.md @@ -4,7 +4,13 @@ title: "Email verification links" # Email verification links -We recommend using [email verification codes](/guides/email-and-password/email-verification-codes) instead as it's more user-friendly. +Email verification works by storing a secret token inside a link. The user's email address is verified when they visit the link. + +``` +https://example.com/email-verification/ +``` + +We recommend using [email verification codes](/guides/email-and-password/email-verification-codes) instead as it's more user-friendly. We also recommend reading through the [email verification guide](https://thecopenhagenbook.com/email-verification) in the Copenhagen Book. ## Update database @@ -153,7 +159,8 @@ app.get("email-verification/:token", async () => { status: 302, headers: { Location: "/", - "Set-Cookie": sessionCookie.serialize() + "Set-Cookie": sessionCookie.serialize(), + "Referrer-Policy": "no-referrer" } }); }); diff --git a/docs/pages/guides/email-and-password/index.md b/docs/pages/guides/email-and-password/index.md index 06ee294b8..5b3446f1f 100644 --- a/docs/pages/guides/email-and-password/index.md +++ b/docs/pages/guides/email-and-password/index.md @@ -13,3 +13,5 @@ Email-based auth requires a lot of components so be prepared to do some work! Fo - [Password reset](/guides/email-and-password/password-reset) - [Login throttling](/guides/email-and-password/login-throttling) - [Two-factor authorization](/guides/email-and-password/2fa) + +We recommend reading through the [password authentication guide](https://thecopenhagenbook.com/password-authentication) in the Copenhagen Book. diff --git a/docs/pages/guides/email-and-password/password-reset.md b/docs/pages/guides/email-and-password/password-reset.md index 18be990fd..d7fae305c 100644 --- a/docs/pages/guides/email-and-password/password-reset.md +++ b/docs/pages/guides/email-and-password/password-reset.md @@ -6,30 +6,35 @@ title: "Password reset" Allow users to reset their password by sending them a reset link to their inbox. +We recommend reading through the [password reset guide](https://thecopenhagenbook.com/password-reset) in the Copenhagen Book. + ## Update database Create a table for storing for password reset tokens. -| column | type | attributes | -| ------------ | -------- | ----------- | -| `id` | `string` | primary key | -| `user_id` | any | | -| `expires_at` | `Date` | | +| column | type | attributes | +| ------------ | -------- | ---------- | +| `token_hash` | `string` | unique | +| `user_id` | any | | +| `expires_at` | `Date` | | ## Create verification token -The token should be valid for at most few hours. +The token should be valid for at most few hours. The token should be hashed before storage as it essentially is a password. SHA-256 can be used here since the token is long and random, unlike user passwords. ```ts import { TimeSpan, createDate } from "oslo"; +import { sha256 } from "oslo/crypto"; +import { encodeHex } from "oslo/encoding"; import { generateId } from "lucia"; async function createPasswordResetToken(userId: string): Promise { // optionally invalidate all existing tokens await db.table("password_reset_token").where("user_id", "=", userId).deleteAll(); const tokenId = generateId(40); + const tokenHash = encodeHex(await sha256(new TextEncoder().encode(tokenId))); await db.table("password_reset_token").insert({ - id: tokenId, + token_hash: tokenHash, user_id: userId, expires_at: createDate(new TimeSpan(2, "h")) }); @@ -68,11 +73,26 @@ Make sure to implement rate limiting based on IP addresses. ## Verify token -Extract the verification token from the URL and validate by checking the expiration date. If the token is valid, invalidate all existing user sessions, update the database, and create a new session. +Make sure to set the `Referrer-Policy` header of the password reset page to `no-referrer` to protect the token from referrer leakage. + +```ts +app.get("/reset-password/:token", async () => { + // ... + return new Response(html, { + headers: { + "Referrer-Policy": "no-referrer" + } + }); +}) +``` + +Extract the verification token from the URL and validate by checking the expiration date. If the token is valid, invalidate all existing user sessions, update the database, and create a new session. Make sure to set the `Referrer-Policy` header here as well. ```ts import { isWithinExpirationDate } from "oslo"; import { Argon2id } from "oslo/password"; +import { sha256 } from "oslo/crypto"; +import { encodeHex } from "oslo/encoding"; app.post("/reset-password/:token", async () => { let password = formData.get("password"); @@ -86,12 +106,14 @@ app.post("/reset-password/:token", async () => { // ... - await db.beginTransaction(); - const token = await db.table("password_reset_token").where("id", "=", verificationToken).get(); + const tokenHash = encodeHex(await sha256(new TextEncoder().encode(verificationToken))); + const token = await db + .table("password_reset_token") + .where("token_hash", "=", tokenHash) + .get(); if (token) { - await db.table("password_reset_token").where("id", "=", verificationToken).delete(); + await db.table("password_reset_token").where("token_hash", "=", tokenHash).delete(); } - await db.commit(); if (!token || !isWithinExpirationDate(token.expires_at)) { return new Response(null, { @@ -111,8 +133,11 @@ app.post("/reset-password/:token", async () => { status: 302, headers: { Location: "/", - "Set-Cookie": sessionCookie.serialize() + "Set-Cookie": sessionCookie.serialize(), + "Referrer-Policy": "no-referrer" } }); }); ``` + + diff --git a/docs/pages/guides/oauth/account-linking.md b/docs/pages/guides/oauth/account-linking.md index 231f3785b..f32075913 100644 --- a/docs/pages/guides/oauth/account-linking.md +++ b/docs/pages/guides/oauth/account-linking.md @@ -13,7 +13,9 @@ In general, you'd want to link accounts with the same email. Keep in mind that t ```ts import { generateId } from "lucia"; -const tokens = await github.validateAuthorizationCode(code); +const tokens = await github.validateAuthorizationCode(code, { + scopes: ["user:email"] +}); const userResponse = await fetch("https://api.github.com/user", { headers: { Authorization: `Bearer ${tokens.accessToken}` diff --git a/docs/pages/guides/oauth/index.md b/docs/pages/guides/oauth/index.md index 5f307e225..9f397d5be 100644 --- a/docs/pages/guides/oauth/index.md +++ b/docs/pages/guides/oauth/index.md @@ -13,3 +13,5 @@ For a step-by-step, framework-specific tutorial, see the [GitHub OAuth](/tutoria - [PKCE](/guides/oauth/pkce) - [Account linking](/guides/oauth/account-linking) - [Custom OAuth providers](/guides/oauth/custom-providers) + +We recommend reading through the [OAuth guide](https://thecopenhagenbook.com/oauth) in the Copenhagen Book. \ No newline at end of file diff --git a/docs/pages/guides/passkeys.md b/docs/pages/guides/passkeys.md index 87d81c83d..75eef3c70 100644 --- a/docs/pages/guides/passkeys.md +++ b/docs/pages/guides/passkeys.md @@ -4,4 +4,6 @@ title: "Passkeys" # Passkeys +Also see the [passkeys guide](https://thecopenhagenbook.com/passkeys) in the Copenhagen Book. + _Work in progress_