-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
docs: add recipe for session and authentication #27287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Changed to relative link Co-authored-by: Sébastien Chopin <seb@nuxtlabs.com>
Co-authored-by: Sébastien Chopin <seb@nuxtlabs.com>
Should we add a link to the downloadable and runnable demo implementation? https://github.com/gearbox-solutions/nuxt-auth-example |
I've made some improvements to the login and registration processes on both the client and server side to work in a more SPA way without a full reload. |
I did not forget it is still in my todo list! |
Well good news! I've just pushed some improvements, so you didn't miss anything. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work!
Just a few things that caught my attention
Co-authored-by: Sébastien Chopin <seb@nuxtlabs.com>
WalkthroughThe pull request introduces a comprehensive guide for implementing sessions and authentication in a Nuxt application using the The changes include the creation of multiple components and configurations:
The guide covers essential aspects of authentication implementation, such as:
The documentation provides a comprehensive approach to implementing a basic authentication system in a Nuxt application, demonstrating how to secure routes, manage user sessions, and handle authentication states using the Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (5)
docs/2.guide/4.recipes/4.sessions-and-authentication.md (5)
8-8
: Fix grammatical issues in the introductionThere are two grammatical issues to address:
- Missing comma after "In this recipe"
- "setup" should be "set up" as it's used as a verb
-In this recipe we'll be setting up authentication in a full-stack Nuxt app using [Nuxt Auth Utils] +In this recipe, we'll be setting up authentication in a full-stack Nuxt app using [Nuxt Auth Utils] -so you don't need to setup a database +so you don't need to set up a databaseAlso applies to: 10-10
🧰 Tools
🪛 LanguageTool
[typographical] ~8-~8: It appears that a comma is missing.
Context: ...uxt app." --- ## Introduction In this recipe we'll be setting up authentication in a...(DURING_THAT_TIME_COMMA)
101-112
: Enhance login form security and user experienceThe current implementation could benefit from improved error handling and user feedback.
Consider these improvements:
+const loading = ref(false) +const error = ref('') async function login() { + error.value = '' + loading.value = true $fetch('/api/login', { method: 'POST', body: credentials }) .then(async () => { await refreshSession() await navigateTo('/') }) - .catch(() => alert('Bad credentials')) + .catch((e) => { + error.value = 'Invalid email or password' + console.error('Login error:', e) + }) + .finally(() => { + loading.value = false + }) }Add to template:
<div v-if="error" class="error">{{ error }}</div> <button type="submit" :disabled="loading"> {{ loading ? 'Logging in...' : 'Login' }} </button>
132-141
: Add request validation and error handling to protected routeThe protected route could benefit from additional validation and error handling.
Consider enhancing the implementation:
export default defineEventHandler(async (event) => { + // Validate query parameters if any + const query = getQuery(event) + const { user } = await requireUserSession(event) - // TODO: Fetch some stats based on the user + try { + // Fetch stats with proper error handling + const stats = await fetchUserStats(user.id) + return stats + } catch (error) { + throw createError({ + statusCode: 500, + message: 'Failed to fetch user stats' + }) + } - return {} })
175-180
: Add type safety and loading state to logout functionalityThe logout implementation could be enhanced with better type safety and user feedback.
Consider these improvements:
+const loading = ref(false) const { user, clear: clearSession } = useUserSession() async function logout() { + loading.value = true try { await clearSession() await navigateTo('/login') + } catch (error) { + console.error('Logout failed:', error) + } finally { + loading.value = false } }
203-203
: Fix grammar in conclusion-Checkout the open source [atidone repository] +Check out the open source [atidone repository]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
docs/2.guide/4.recipes/4.sessions-and-authentication.md
(1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/2.guide/4.recipes/4.sessions-and-authentication.md
[typographical] ~8-~8: It appears that a comma is missing.
Context: ...uxt app." --- ## Introduction In this recipe we'll be setting up authentication in a...
(DURING_THAT_TIME_COMMA)
[grammar] ~10-~10: The word “setup” is a noun. The verb is spelled with a space.
Context: ...tore session data, so you don't need to setup a database to store session data. ## I...
(NOUN_VERB_CONFUSION)
[uncategorized] ~19-~19: Loose punctuation mark.
Context: ... nuxi@latest module add auth-utils ``` ::callout This command will install `nuxt...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~27-~27: Loose punctuation mark.
Context: ...ESSION_PASSWORD` environment variable. ::note If not set, this environment varia...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~29-~29: Loose punctuation mark.
Context: ...cally when running in development mode. :: ```dotenv [.env] NUXT_SESSION_PASSWOR...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~35-~35: Loose punctuation mark.
Context: ...ssword-with-at-least-32-characters ``` ::important You'll need to add this envir...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~37-~37: Loose punctuation mark.
Context: ...roduction environment before deploying. :: ## Login API Route For this recipe, ...
(UNLIKELY_OPENING_PUNCTUATION)
[grammar] ~42-~42: The word “sign-in” is a noun. The verb is spelled with a white space.
Context: ...ipe, we'll create a simple API route to sign-in a user based on static data. Let's cre...
(NOUN_VERB_CONFUSION)
[uncategorized] ~73-~73: Loose punctuation mark.
Context: ...message: 'Bad credentials' }) }) ``` ::callout Make sure to install the zod
...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~75-~75: Loose punctuation mark.
Context: ...pendency in your project (npm i zod
). :: ::tip{to="https://github.com/atinux/n...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~77-~77: Loose punctuation mark.
Context: ...ency in your project (npm i zod
). :: ::tip{to="https://github.com/atinux/nuxt-...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~79-~79: Loose punctuation mark.
Context: ...er helper exposed by nuxt-auth-utils
. :: ## Login Page The module exposes a V...
(UNLIKELY_OPENING_PUNCTUATION)
[misspelling] ~165-~165: The word ‘informations’ is a legal term. In standard English, the word ‘information’ is a non-count noun.
Context: ...age that display our authenticated user informations. If the user is not authenticated, they...
(INFORMATIONS)
[grammar] ~202-~202: This sentence should probably be started with a verb instead of the noun ‘Checkout’. If not, consider inserting a comma for better clarity.
Context: ...s?tab=readme-ov-file#webauthn-passkey) Checkout the open source [atidone repository](ht...
(SENT_START_NN_DT)
```dotenv [.env] | ||
NUXT_SESSION_PASSWORD=a-random-password-with-at-least-32-characters | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance security guidance for session password
The environment variable section should include stronger security recommendations.
Add the following security notes after line 34:
::warning
Ensure that your session password:
- Is unique for each deployment environment
- Is randomly generated
- Is at least 32 characters long
- Is stored securely in your deployment platform's environment variables
- Is not committed to version control
::
if (email === 'admin@admin.com' && password === 'iamtheadmin') { | ||
// set the user session in the cookie | ||
// this server util is auto-imported by the auth-utils module | ||
await setUserSession(event, { | ||
user: { | ||
name: 'John Doe' | ||
} | ||
}) | ||
return {} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add security measures to login endpoint
The current implementation has several security considerations:
- Hardcoded credentials should not be used in production
- Missing rate limiting for brute force protection
- Missing security headers
Replace the static credentials check with a proper user validation and add security measures:
- if (email === 'admin@admin.com' && password === 'iamtheadmin') {
+ // Add rate limiting
+ const rateLimiter = useRateLimiter(event)
+ await rateLimiter.limit()
+
+ // Add security headers
+ setHeader(event, 'X-Frame-Options', 'DENY')
+ setHeader(event, 'X-Content-Type-Options', 'nosniff')
+
+ // Validate user from database
+ const user = await validateUser(email, password)
+ if (user) {
await setUserSession(event, {
- user: {
- name: 'John Doe'
- }
+ user: { id: user.id, name: user.name }
})
return {}
}
Would you like me to create a GitHub issue to track the implementation of these security measures?
Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
docs/2.guide/4.recipes/4.sessions-and-authentication.md (4)
111-111
: Enhance error handling in login formUsing
alert()
for error feedback provides poor user experience. Consider implementing a more user-friendly error display mechanism.- .catch(() => alert('Bad credentials')) + .catch((error) => { + const errorMessage = error.data?.message || 'Login failed. Please try again.' + // Update UI state to show error message + credentials.error = errorMessage + })Additionally, consider adding:
- Loading state during form submission
- Disable form submission while processing
- Clear error message when user starts typing
175-180
: Add type safety and error handling to logout operationThe current implementation lacks type safety and proper error handling.
-const { user, clear: clearSession } = useUserSession() +interface User { + name: string; + // Add other user properties +} + +const { user, clear: clearSession } = useUserSession<User>() async function logout() { + try { await clearSession() await navigateTo('/login') + } catch (error) { + console.error('Logout failed:', error) + // Handle error appropriately + } }
203-203
: Add link to demo implementationConsider adding a link to the demo implementation of this authentication recipe.
Checkout the open source [atidone repository](https://github.com/atinux/atidone) for a full example of a Nuxt app with OAuth authentication, database and CRUD operations. + +You can also explore a live demo of this authentication recipe at [nuxt-auth-example](https://github.com/gearbox-solutions/nuxt-auth-example).
165-165
: Fix grammar and typography issuesThere are a few grammar issues that need attention:
-Now that we have our app middleware to protect our routes, we can use it on our home page that display our authenticated user informations. +Now that we have our app middleware to protect our routes, we can use it on our home page that displays our authenticated user information. -Checkout the open source [atidone repository] +Check out the open source [atidone repository]Also applies to: 202-202
🧰 Tools
🪛 LanguageTool
[misspelling] ~165-~165: The word ‘informations’ is a legal term. In standard English, the word ‘information’ is a non-count noun.
Context: ...age that display our authenticated user informations. If the user is not authenticated, they...(INFORMATIONS)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
docs/2.guide/4.recipes/4.sessions-and-authentication.md
(1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/2.guide/4.recipes/4.sessions-and-authentication.md
[typographical] ~8-~8: It appears that a comma is missing.
Context: ...uxt app." --- ## Introduction In this recipe we'll be setting up authentication in a...
(DURING_THAT_TIME_COMMA)
[grammar] ~10-~10: The word “setup” is a noun. The verb is spelled with a space.
Context: ...tore session data, so you don't need to setup a database to store session data. ## I...
(NOUN_VERB_CONFUSION)
[uncategorized] ~19-~19: Loose punctuation mark.
Context: ... nuxi@latest module add auth-utils ``` ::callout This command will install `nuxt...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~27-~27: Loose punctuation mark.
Context: ...ESSION_PASSWORD` environment variable. ::note If not set, this environment varia...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~29-~29: Loose punctuation mark.
Context: ...cally when running in development mode. :: ```dotenv [.env] NUXT_SESSION_PASSWOR...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~35-~35: Loose punctuation mark.
Context: ...ssword-with-at-least-32-characters ``` ::important You'll need to add this envir...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~37-~37: Loose punctuation mark.
Context: ...roduction environment before deploying. :: ## Login API Route For this recipe, ...
(UNLIKELY_OPENING_PUNCTUATION)
[grammar] ~42-~42: The word “sign-in” is a noun. The verb is spelled with a white space.
Context: ...ipe, we'll create a simple API route to sign-in a user based on static data. Let's cre...
(NOUN_VERB_CONFUSION)
[uncategorized] ~73-~73: Loose punctuation mark.
Context: ...message: 'Bad credentials' }) }) ``` ::callout Make sure to install the zod
...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~75-~75: Loose punctuation mark.
Context: ...pendency in your project (npm i zod
). :: ::tip{to="https://github.com/atinux/n...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~77-~77: Loose punctuation mark.
Context: ...ency in your project (npm i zod
). :: ::tip{to="https://github.com/atinux/nuxt-...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~79-~79: Loose punctuation mark.
Context: ...er helper exposed by nuxt-auth-utils
. :: ## Login Page The module exposes a V...
(UNLIKELY_OPENING_PUNCTUATION)
[misspelling] ~165-~165: The word ‘informations’ is a legal term. In standard English, the word ‘information’ is a non-count noun.
Context: ...age that display our authenticated user informations. If the user is not authenticated, they...
(INFORMATIONS)
[grammar] ~202-~202: This sentence should probably be started with a verb instead of the noun ‘Checkout’. If not, consider inserting a comma for better clarity.
Context: ...s?tab=readme-ov-file#webauthn-passkey) Checkout the open source [atidone repository](ht...
(SENT_START_NN_DT)
🔇 Additional comments (2)
docs/2.guide/4.recipes/4.sessions-and-authentication.md (2)
32-34
: Enhance security guidance for session password
The environment variable section should include stronger security recommendations.
```dotenv [.env]
NUXT_SESSION_PASSWORD=a-random-password-with-at-least-32-characters
+::warning
+Ensure that your session password:
+- Is unique for each deployment environment
+- Is randomly generated
+- Is at least 32 characters long
+- Is stored securely in your deployment platform's environment variables
+- Is not committed to version control
+::
---
`57-66`: **Add security measures to login endpoint**
The current implementation has several security considerations that should be addressed:
```diff
- if (email === 'admin@admin.com' && password === 'iamtheadmin') {
+ // Add rate limiting
+ const rateLimiter = useRateLimiter(event)
+ await rateLimiter.limit()
+
+ // Add security headers
+ setHeader(event, 'X-Frame-Options', 'DENY')
+ setHeader(event, 'X-Content-Type-Options', 'nosniff')
+
+ // Validate user from database
+ const user = await validateUser(email, password)
+ if (user) {
await setUserSession(event, {
- user: {
- name: 'John Doe'
- }
+ user: { id: user.id, name: user.name }
})
return {}
}
|
||
## Protect API Routes | ||
|
||
Protecting server routes is key to making sure your data is safe. Client-side middleware is helpful for the user, but without server-side protection your data can still be accessed. It is critical to protect any routes with sensitive data, we should return a 401 error if the user is not logged in on those. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance security guidance for route protection
The documentation should mention additional security considerations for protecting routes.
Add the following security notes:
Protecting server routes is key to making sure your data is safe. Client-side middleware is helpful for the user, but without server-side protection your data can still be accessed. It is critical to protect any routes with sensitive data, we should return a 401 error if the user is not logged in on those.
+
+::warning
+Additional security considerations:
+- Ensure cookies are set with HTTP-only flag
+- Implement CSRF protection for state-changing operations
+- Consider implementing request origin validation
+- Add rate limiting for sensitive operations
+::
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
Protecting server routes is key to making sure your data is safe. Client-side middleware is helpful for the user, but without server-side protection your data can still be accessed. It is critical to protect any routes with sensitive data, we should return a 401 error if the user is not logged in on those. | |
Protecting server routes is key to making sure your data is safe. Client-side middleware is helpful for the user, but without server-side protection your data can still be accessed. It is critical to protect any routes with sensitive data, we should return a 401 error if the user is not logged in on those. | |
::warning | |
Additional security considerations: | |
- Ensure cookies are set with HTTP-only flag | |
- Implement CSRF protection for state-changing operations | |
- Consider implementing request origin validation | |
- Add rate limiting for sensitive operations | |
:: |
Thank you both ❤️ |
Co-authored-by: Sébastien Chopin <atinux@gmail.com>
Co-authored-by: Sébastien Chopin <atinux@gmail.com>
This PR adds a recipe example for managing user sessions using
nuxt-auth-utils
.Database queries are managed with Drizzle, which I'm trying for the first time here. I'm not entirely sold on this after using it, though, and could probably rewrite this with something like Sequelize or TypeORM if that would be preferred.
I've also posted a more robust example repo. Would it be good to link to this? This could be updated to use Sequelize/TypeORM as well.