The Series
- Drizzle ORM, SQLite and Nuxt JS - Getting Started
- Drizzle ORM SQLite and Nuxt - Integrating Nuxt Auth, Part 1
- 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
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
}
})
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
}
}
})
]
})
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>
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>
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>
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!' }
}
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>
Links
- Sidebase Nuxt-Auth -https://sidebase.io/nuxt-auth/getting-started
- Drizzle Quick Start - https://orm.drizzle.team/docs/quick-start
- Drizzle Kit - https://orm.drizzle.team/kit-docs/overview
- Drizzle ORM Sqlite - https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sqlite-core/README.md
- Better Sqlite 3 - https://github.com/WiseLibs/better-sqlite3
Social Media
- Twitter - https://twitter.com/aaronksaunders
- Facebook - https://www.facebook.com/ClearlyInnovative
- Instagram - https://www.instagram.com/aaronksaunders
- Dev.to - https://dev.to/aaronksaunders
- YouTube - https://www.youtube.com/@Aaronsaundersci