Nuxt
Authentication

Authentication

supastarter integrates Lucia Auth (opens in a new tab) for authentication. It is a lightweight authentication library that gives you full control over your authentication flow.

💡

Why Lucia Auth:
One of the central principles of supastarter is full control over every aspect of your application. Lucia Auth takes away the complexity of authentication while giving you full flexibility over the authentication flow. It is also a popular library with a growing community and is actively maintained.

You can read more about Lucia Auth in the offical docs (opens in a new tab).

Here is an overview over the user schema of supastarter:

User schema

Add oAuth provider

supastarter comes with two example providers out of the box: GitHub and Google. You can find a list of all available providers in the artic documentation (opens in a new tab) (which is part of Lucia).

As an example, we will add Facebook as an oAuth provider.

First go to the Facebook developer console (opens in a new tab) and create a new app.

Add the credentials to your .env.local file:

FACEBOOK_CLIENT_ID=your-client-id
FACEBOOK_CLIENT_SECRET=your-client-secret

Then create a new file packages/auth/oauth/facebook.ts with the following content:

import { Facebook, generateState } from 'arctic';
import { getBaseUrl } from 'utils';
import { createOauthCallbackHandler, createOauthRedirectHandler } from '../lib/oauth';
 
export const facebookAuth = new Facebook(
  process.env.FACEBOOK_CLIENT_ID!,
  process.env.FACEBOOK_CLIENT_SECRET!,
  new URL('/api/oauth/facebook/callback', getBaseUrl()).toString()
);
 
const FACEBOOK_PROIVDER_ID = 'facebook';
 
type FacebookUser = {
  id: string;
  email: string;
  picture?: string;
  name: string;
};
 
export const facebookRouteHandler = createOauthRedirectHandler(FACEBOOK_PROIVDER_ID, async () => {
  const state = generateState();
 
  const url = await facebookAuth.createAuthorizationURL(state, {
    scopes: ['user:email'],
  });
 
  return {
    state,
    url,
  };
});
 
export const facebookCallbackRouteHandler = createOauthCallbackHandler(FACEBOOK_PROIVDER_ID, async (code) => {
  const tokens = await facebookAuth.validateAuthorizationCode(code);
 
  const url = new URL('https://graph.facebook.com/me');
  url.searchParams.set('access_token', tokens.accessToken);
  url.searchParams.set('fields', ['id', 'name', 'picture', 'email'].join(','));
  const facebookUserResponse = await fetch(url, {
    headers: {
      Authorization: `Bearer ${tokens.accessToken}`,
    },
  });
 
  const facebookUser = (await facebookUserResponse.json()) as FacebookUser;
 
  return {
    id: String(facebookUser.id),
    email: facebookUser.email,
    name: facebookUser.name,
    avatar: facebookUser.picture,
  };
});

In this file we define two handlers:

  1. facebookRouteHandler: This handler is responsible for redirecting the user to the Facebook login page.

  2. facebookCallbackRouteHandler: This handler is responsible for handling the callback from Facebook. It validates the authorization code and retrieves the user information. If the user already exists in the database, it creates a session for the user. If the user does not exist, it creates a new user and a session for the user.

You can more about how to get the authorization code, how to validate it and how to fetch the user data for each provider in the artic documentation (opens in a new tab).

Now we only need to create to route handlers in our Next.js app.

Create one file for the redirect handler apps/web/server/api/oauth/facebook/index.get.ts:

export { facebookRouteHandler as GET } from 'auth/oauth/facebook';

And another file for the callback handler apps/web/server/api/oauth/facebook/callback.get.ts:

export { facebookCallbackRouteHandler as GET } from 'auth/oauth/facebook';

The last thing you need to the oAuthProviders object in the apps/web/modules/saas/auth/components/SaasSocialSigninButton.client.vue:

export const oAuthProviders = {
  // ...
  facebook: {
    name: 'Facebook',
    icon: ({ ...props }: IconProps) => (
      // grab the svg from https://simpleicons.org/
      <svg {...props} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
        <path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z" />
      </svg>
    ),
  },
};