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.