Documentation
Authentication

oAuth

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 (which is part of Lucia).

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

First go to the Facebook developer console 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.

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

Create one file for the redirect handler apps/web/app/api/oauth/facebook/route.ts:

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

And another file for the callback handler apps/web/app/api/oauth/facebook/callback/route.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/SocialSigninButton.tsx:

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>
    ),
  },
};

On this page