Docs
Authentication

Authentication

Authentication and authorization

SaaSKits provides a simple Authentication and Authorization system that can be used to secure your application.

SaaSKits uses Remix Auth under the hood, so you can use all the features provided by it.

We provide two ways to authenticate your users:

  • Email and password
  • Google OAuth

However, you can customize the authentication system to use any other provider you want.

Remix Auth uses Remix's session to store the user information, so you can access it from any page or endpoint.

import { createCookieSessionStorage } from "@remix-run/node"
 
// export the whole sessionStorage object
export let sessionStorage = createCookieSessionStorage({
  cookie: {
    name: "_session", // use any name you want here
    sameSite: "lax", // this helps with CSRF
    path: "/", // remember to add this so the cookie will work in all routes
    httpOnly: true, // for security reasons, make this cookie http only
    secrets: [process.env.SESSION_SECRET!], // replace this with an actual secret
    secure: process.env.NODE_ENV === "production", // enable this in prod only
  },
})
 
// you can also export the methods individually for your own usage
export let { getSession, commitSession, destroySession } = sessionStorage

Create an instance of the Authenticator class and pass it to the authenticator function.

import { Authenticator } from "@remix-run/auth"
 
export let authenticator = new Authenticator<User>(sessionStorage)

Email and password

For email and password authentication, we use Remix Auth Form.

 
......
const formStrategy = new FormStrategy(async ({ form, context }) => {
......

Google OAuth

For Google OAuth, we use Remix Auth Google.

 
......
const googleStrategy = new GoogleStrategy(
  {
    clientID: process.env.GOOGLE_CLIENT_ID || "",
    clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
    callbackURL: process.env.HOST_URL
      ? `${process.env.HOST_URL}/google/callback`
      : "http://localhost:3000/google/callback",
  },
  async ({ accessToken, refreshToken, extraParams, profile }) => {
......

Protecting routes

To protect a route, you can use the authenticator.isAuthenticated method.

.....
export const loader = async ({ request }: LoaderFunctionArgs) => {
  const session = await authenticator.isAuthenticated(request, {
    failureRedirect: "/login",
  })
 
  const user = await getUserById(session.id)
 
  if (!user) {
    return redirect("/login")
  }
 
   return json({ user })
 
}
.....

Protecting Actions

To protect an action, you can use the authenticator.isAuthenticated method.

.....
 
export const action = async ({ request }: ActionFunctionArgs) => {
    const session = await authenticator.isAuthenticated(request, {
        failureRedirect: "/login",
    })
    
    const user = await getUserById(session.id)
    
    if (!user) {
        return redirect("/login")
    }
    
    return json({ user })
    }
 
.....
    

Adding a new provider is as simple as creating a new strategy and passing it to the authenticator function.

There are plenty of available options for each strategy, so make sure to check the documentation of each one.