Setting up authentication in Astro with Prisma and Planetscale

I’ve been wanting to add authentication to my personal website for a while now to see how it works in Astro.
With Prisma and PlanetScale already running for comments on my blogs, I decided to store my account information in PlanetScale.
Because it’s ju…


This content originally appeared on DEV Community and was authored by Thomas Ledoux

I've been wanting to add authentication to my personal website for a while now to see how it works in Astro.
With Prisma and PlanetScale already running for comments on my blogs, I decided to store my account information in PlanetScale.
Because it's just used for my own account, and I'm not storing any other sensitive information in my database, I decided to store the credentials in plain text for now.
I changed my Prisma schema to make this possible:

// schema.prisma

model Account {
  id Int @id @default(autoincrement())
  username String @unique
  password String
}

Once the model is updated in the code, running npx prisma db push propagates the changes to PlanetScale, so the schema is updated in the actual database.

I used an existing package called @astro-auth to handle all the authentication on my site.
For this to work, I needed to add 2 environment variables to my application: ASTROAUTH_URL (the URL my site is hosted on) and ASTROAUTH_SECRET (a self chosen secret key).

Because I stored the credentials in PlanetScale, I needed to use the CredentialProvider to enable logging in with username and password.
There are many other providers available on @astro-auth, go check out the package if you're interested.
The code needed to set this up with @astro-auth looks like this:

// /pages/api/auth/[...astroauth].ts

import AstroAuth from '@astro-auth/core';
import { CredentialProvider } from '@astro-auth/providers';
import { prisma } from '../../../lib/prisma';

export const all = AstroAuth({
  authProviders: [
    CredentialProvider({
      authorize: async properties => {
        const account = await prisma?.account.findFirst({
          where: {
            username: properties.username,
            AND: {
              password: properties.password,
            },
          },
          select: {
            id: true,
          },
        });
        if (account?.id) {
          return properties.username;
        }
        return null;
      },
    }),
  ],
});

Creating a login page was very easy.
I just created a form, calling the signIn() method from @astro-auth on submit, and BOOM: logged in!
The code for the login page:

// /pages/login.astro

<html>
  <head>
    <title>Login</title>
    <script>
      import { signIn } from '@astro-auth/client';

      document.addEventListener('DOMContentLoaded', () => {
        document.querySelector('form')?.addEventListener('submit', async e => {
          e.preventDefault();
          const form = e.target;
          if (form) {
            const formData = new FormData(form as HTMLFormElement);
            const data = Object.fromEntries(formData);
            await signIn({
              provider: 'credential',
              login: data,
            });
            window.location.href = '/';
          }
        });
      });
    </script>
  </head>
  <body>
    <form>
      <label for="username">Name</label>
      <input type="text" name="username" />

      <label for="password">Password</label>
      <input type="password" name="password" />

      <input type="submit" value="Submit" />
    </form>
  </body>
</html>

After submitting the form, the user's signed in and is redirected to the homepage.
Protecting a page with authentication is easy, just checking the logged in user with the getUser() function from @astro-auth.
Here's an example of a page where I used this check:

// /pages/comment-overview.astro

---
import { getUser } from '@astro-auth/core';
import Layout from '../layouts/Layout.astro';
import { prisma } from '../lib/prisma';
import CommentsOverviewWrapper from '../components/CommentOverviewWrapper';
const user = getUser({ client: Astro });
if (!user) {
  return Astro.redirect('/', 307);
}
const commentsWithPost = await prisma?.comment.findMany({
  include: {
    post: {
      select: {
        url: true,
      },
    },
  },
});
---

<Layout
  description="Overview of comments"
  title="Thomas Ledoux | Comment overview"
>
  <CommentsOverviewWrapper commentsWithPost={commentsWithPost} client:load />
</Layout>

If the user is not logged in, the user will be redirected to the homepage with a 307 status code.
I also have an API route to delete comments on my blog posts, which I want to fence off so only authenticated user can use this API.
It's possible to use the getUser() function from @astro-auth for this too, but this time we're going to pass the request instead of the Astro object.
Example of using this code:

// /pages/api/comments.ts

export const del: APIRoute = async ({ request }) => {
  const user = getUser({ server: request });
  if (user) {
    const body = await request.json();
    const deleteComment = await prisma?.comment.delete({
      where: {
        id: body.id,
      },
    });
    return new Response(
      JSON.stringify({
        message: `Comment with id ${deleteComment?.id} deleted`,
      }),
      { status: 200 }
    );
  }
  return new Response(null, { status: 403 });
};

So when the user is not authenticated, a 403 response will be returned.

Hope this was helpful!
Source code can be found on my Github as always.


This content originally appeared on DEV Community and was authored by Thomas Ledoux


Print Share Comment Cite Upload Translate Updates
APA

Thomas Ledoux | Sciencx (2023-02-26T16:22:26+00:00) Setting up authentication in Astro with Prisma and Planetscale. Retrieved from https://www.scien.cx/2023/02/26/setting-up-authentication-in-astro-with-prisma-and-planetscale/

MLA
" » Setting up authentication in Astro with Prisma and Planetscale." Thomas Ledoux | Sciencx - Sunday February 26, 2023, https://www.scien.cx/2023/02/26/setting-up-authentication-in-astro-with-prisma-and-planetscale/
HARVARD
Thomas Ledoux | Sciencx Sunday February 26, 2023 » Setting up authentication in Astro with Prisma and Planetscale., viewed ,<https://www.scien.cx/2023/02/26/setting-up-authentication-in-astro-with-prisma-and-planetscale/>
VANCOUVER
Thomas Ledoux | Sciencx - » Setting up authentication in Astro with Prisma and Planetscale. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/02/26/setting-up-authentication-in-astro-with-prisma-and-planetscale/
CHICAGO
" » Setting up authentication in Astro with Prisma and Planetscale." Thomas Ledoux | Sciencx - Accessed . https://www.scien.cx/2023/02/26/setting-up-authentication-in-astro-with-prisma-and-planetscale/
IEEE
" » Setting up authentication in Astro with Prisma and Planetscale." Thomas Ledoux | Sciencx [Online]. Available: https://www.scien.cx/2023/02/26/setting-up-authentication-in-astro-with-prisma-and-planetscale/. [Accessed: ]
rf:citation
» Setting up authentication in Astro with Prisma and Planetscale | Thomas Ledoux | Sciencx | https://www.scien.cx/2023/02/26/setting-up-authentication-in-astro-with-prisma-and-planetscale/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.