Authentication
Vivid brings way to authenticate and storing the user's session. You can customize the authentication flow by modifying the auth
plugin.
Prequesties
Before using any of the authentication features, you need to define some types to ensure type safety.
import { type Rules } from './casl';
export type User = {
id: string;
name: string;
abilities: Rules;
role: 'admin' | 'user';
image?: string;
};
export type SignInOptions = {
name: string;
password: string;
};
Rules
type comes from ACL feature in Vivid. You can read more about it in Access Control.
Both User
and SignInOptions
are required to be defined before using the authentication features as it will be used throughout the app.
Resolving User
This function will be always called when initializing the app. You can use it to resolve the user's session.
import { defineResolve } from '@/lib/core/auth';
// ...
export const resolve = defineResolve(async () => {
// mocked user
const res = await axios.get<User>('/me');
const user = res.data;
ability.update(user.abilities);
return user;
});
Read more about Access Control.
Signing In
While you entirely manages how users sign in, Vivid will automatically handles the session and the user's data.
import { defineSignIn } from '@/lib/core/auth';
// ...
export const signIn = defineSignIn<SignInOptions>(async (data) => {
// mocked user
const res = await axios.post<User>('/login', data);
const user = res.data;
ability.update(user.abilities);
return user;
});
Read more about Access Control.
Usage
After defining the signIn
function, you can use it in your components.
import { signIn } from '@auth';
import { useForm } from '@mantine/form';
import { useNavigate } from '@/router/utils';
export default function Login() {
// ...
const navigate = useNavigate();
const form = useForm({
initialValues: {
name: '',
password: '',
},
validate: {
name: (value) => value.trim().length <= 0 && 'Name is required',
password: (value) => value.trim().length <= 0 && 'Password is required',
},
});
const onSubmit = form.onSubmit(async (values) => {
const u = await signIn(values);
if (!u) {
form.setErrors({
name: 'Not allowed',
password: 'Not allowed',
});
}
navigate('/');
});
// ...
}
Read more about Mantine Form.
Signing Out
Similar to signing in, you can define the signOut
function to handle the sign out process. The difference is, this function acts as a middleware before the user is actually logged out.
import { defineSignOut } from '@/lib/core/auth';
import { axios } from '@axios';
export const signOut = defineSignOut(async (user) => {
// Do something with user before actually logged out
// Example: send a request to the server to invalidate the session
axios.post('/logout', user);
});
Read more about data fetching in Data Fetching.
Usage
You can use the signOut
function in your components, for example:
import { ActionIcon } from '@mantine/core';
import { SignOut } from '@phosphor-icons/react';
import { signOut } from '@auth';
export const SignOutButton = () => (
<ActionIcon color="red">
<SignOut weight="bold" size={20} onClick={signOut} />
</ActionIcon>
);