Skip to content

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

Merged
merged 25 commits into from
Dec 20, 2024
Merged

docs: add recipe for session and authentication #27287

merged 25 commits into from
Dec 20, 2024

Conversation

Smef
Copy link
Contributor

@Smef Smef commented May 21, 2024

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.

Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@Smef Smef changed the title docs: Add recipe for session and authentication docs: add recipe for session and authentication May 21, 2024
@danielroe danielroe requested a review from atinux May 21, 2024 08:18
Smef and others added 2 commits May 22, 2024 19:39
Changed to relative link

Co-authored-by: Sébastien Chopin <seb@nuxtlabs.com>
Co-authored-by: Sébastien Chopin <seb@nuxtlabs.com>
@Smef
Copy link
Contributor Author

Smef commented May 22, 2024

Should we add a link to the downloadable and runnable demo implementation? https://github.com/gearbox-solutions/nuxt-auth-example

@Smef
Copy link
Contributor Author

Smef commented Jun 5, 2024

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.

Copy link
Member

atinux commented Jun 10, 2024

I did not forget it is still in my todo list!

@Smef
Copy link
Contributor Author

Smef commented Jun 10, 2024

Well good news! I've just pushed some improvements, so you didn't miss anything.

Copy link
Contributor

@GalacticHypernova GalacticHypernova left a 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

@Smef Smef requested a review from danielroe as a code owner July 15, 2024 16:10
@danielroe danielroe requested a review from atinux July 15, 2024 16:25
Co-authored-by: Sébastien Chopin <seb@nuxtlabs.com>
@danielroe danielroe requested a review from atinux December 19, 2024 11:32
Copy link

coderabbitai bot commented Dec 20, 2024

Walkthrough

The pull request introduces a comprehensive guide for implementing sessions and authentication in a Nuxt application using the nuxt-auth-utils module. The documentation provides a detailed walkthrough of setting up user authentication without requiring a database, focusing on secure session management through encrypted cookies.

The changes include the creation of multiple components and configurations:

  1. A new login API route that validates user credentials.
  2. A user statistics API route protected by authentication.
  3. A client-side middleware for handling authenticated routes.
  4. Page metadata modifications to support authentication flows.

The guide covers essential aspects of authentication implementation, such as:

  • Module installation.
  • Environment variable configuration for session encryption.
  • Login page implementation.
  • API route protection mechanisms.
  • Client-side session management.
  • Middleware for redirecting unauthenticated users.

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 nuxt-auth-utils module.


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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a 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 introduction

There are two grammatical issues to address:

  1. Missing comma after "In this recipe"
  2. "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 database

Also 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 experience

The 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 route

The 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 functionality

The 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

📥 Commits

Reviewing files that changed from the base of the PR and between c260eaa and dff1b09.

📒 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)

Comment on lines +32 to +34
```dotenv [.env]
NUXT_SESSION_PASSWORD=a-random-password-with-at-least-32-characters
```
Copy link

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
::

Comment on lines +57 to +66
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 {}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add security measures to login endpoint

The current implementation has several security considerations:

  1. Hardcoded credentials should not be used in production
  2. Missing rate limiting for brute force protection
  3. 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.

Copy link

@coderabbitai coderabbitai bot left a 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 form

Using 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 operation

The 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 implementation

Consider 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 issues

There 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

📥 Commits

Reviewing files that changed from the base of the PR and between dff1b09 and 35ae28f.

📒 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.
Copy link

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.

Suggested change
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
::

@danielroe danielroe merged commit 62e19c2 into nuxt:main Dec 20, 2024
7 checks passed
@danielroe
Copy link
Member

Thank you both ❤️

@github-actions github-actions bot mentioned this pull request Dec 20, 2024
danielroe pushed a commit that referenced this pull request Dec 23, 2024
Co-authored-by: Sébastien Chopin <atinux@gmail.com>
@github-actions github-actions bot mentioned this pull request Dec 23, 2024
Kamsou pushed a commit to Kamsou/nuxt that referenced this pull request Feb 5, 2025
Co-authored-by: Sébastien Chopin <atinux@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy