Drizzle ORM SQLite and Nuxt - Integrating Nuxt Auth, Part 1

Aaron K Saunders - Aug 10 '23 - - Dev Community

The Series

  1. Drizzle ORM, SQLite and Nuxt JS - Getting Started
  2. Drizzle ORM SQLite and Nuxt - Integrating Nuxt Auth, Part 1
  3. Drizzle ORM SQLite and Nuxt - Integrating Nuxt Auth, Part 2

Overview

In this series, we will use the package @sidebase/nuxt-auth - to implement email + password authentication in the application. We will create login and register API routes that utilize Drizzle ORM connected to an SQLite Database

This blog post is a walkthrough of the code added to the application as we work though the video, meaning this is a companion post to support the video

VIDEO

see first video in series here Drizzle ORM SQLite and Nuxt

Install Sidebase Nuxt Auth

in your nuxt project directory run the follwoing commands to install the nuxt-auth module and dependencies

npm i -D @sidebase/nuxt-auth
npm i -D next-auth@4.21.1
Enter fullscreen mode Exit fullscreen mode

Configure Project

Add the module, and add additional property to use global auth middleware by default; meaning that you must be authenticated to access any page in the app.

export default defineNuxtConfig({
   modules: ['@sidebase/nuxt-auth'],
   auth : {
    globalAppMiddleware: false
   }
})
Enter fullscreen mode Exit fullscreen mode

Add NuxtAuthHandler

Since we are using the credentials provider, i discovered local provider later in the process will investigate later.

the file needs to be at a specific path server/api/auth/[...].ts

// file: ~/server/api/auth/[...].ts
import CredentialsProvider from 'next-auth/providers/credentials'
import { NuxtAuthHandler } from '#auth'

export default NuxtAuthHandler({
  // A secret string you define, to ensure correct encryption
  secret: 'your-secret-here',
  providers: [
    // @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point
    CredentialsProvider.default({

      credentials: {
        username: { label: 'Username', type: 'text', placeholder: '(hint: jsmith)' },
        password: { label: 'Password', type: 'password', placeholder: '(hint: hunter2)' }
      },
      authorize (credentials: any) {

        const user = { id: '1', name: 'J Smith', username: 'jsmith', password: 'hunter2' }

        if (credentials?.username === user.username && credentials?.password === user.password) {
          // Any object returned will be saved in `user` property of the JWT
          return user
        } else {
          // eslint-disable-next-line no-console
          console.error('Warning: Malicious login attempt registered, bad credentials provided')

          return null

        }
      }
    })
  ]
})

Enter fullscreen mode Exit fullscreen mode

Now lets add a protected page so we have something to see when we authenticate a user.

we will delete the app.vue file from the project directory and create a pages directory and add a file named index.vue with the following contents

<template>
  WELCOME TO MY APP
</template>
<script setup lang="ts">
</script>
Enter fullscreen mode Exit fullscreen mode

Now after you login to the application you should be redirected to this page. If you try to go directly to the index.vue page you will be re-routed to the default login page created by nuxt-auth

Session Data and More From useAuth

We can use the useAuth composable to get information from the nuxt-auth service in your application. We to get some information from the session so we use the composable like this, where the session information is in data and the authentication state is in status

<template>
  WELCOME TO MY APP
  <p>DATA: {{ JSON.stringify(data) }}</p>
  <p>AUTH STATUS: {{ status }}</p>
</template>
<script setup lang="ts">
const { data, status } = useAuth();

const { data: users } = useFetch("/api/users");
</script>
Enter fullscreen mode Exit fullscreen mode

Adding SignOut

We can use the useAuth composable to access helper functions from the nuxt-auth service in your application, in this case we need the signOut function.

In the code below we added a button and are calling the signout method when the button is clicked.

<template>
  WELCOME TO MY APP

  <p>DATA: {{ JSON.stringify(data) }}</p>
  <p>AUTH STATUS: {{ status }}</p>

  <button @click="() => signOut()">
     SIGN OUT
  </button>
</template>
<script setup lang="ts">
const { data, status, signOut } = useAuth();

const { data: users } = useFetch("/api/users");
</script>
Enter fullscreen mode Exit fullscreen mode

Demonstrating Protected API Routes

In the video we test this by adding the following code to the users.get.ts route and trying to access the route using Thunder Client or any REST API client.

You will get the unauthenticated status response because there is no session information.

import { getServerSession } from '#auth'

...

  const session = await getServerSession(event)
  if (!session) {
    return { status: 'unauthenticated!' }
  }
Enter fullscreen mode Exit fullscreen mode

When you change the code in index.vue to do the same query, it will work because to get to the index.vue page, the user must be authenticated.

This is the code for the updated index.vue page.

<template>
  WELCOME TO MY APP

  <p>DATA: {{ JSON.stringify(data) }}</p>
  <p>STATUS: {{ status }}</p>

  <pre>USERS: {{ JSON.stringify(users, null,2) }}</pre>

  <button @click="() => signOut()">
    SIGN OUT
  </button>
</template>
<script setup lang="ts">
const { data, status, signOut } = useAuth();

const { data: users } = useFetch("/api/users");
</script>
Enter fullscreen mode Exit fullscreen mode

Links

Social Media

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .