Authentication

Session

Learn how to manage the user session in your extension.

We're not implementing fully-featured auth flow in the extension. Instead, we're sharing the same auth session with the web app.

It's a common practice in the industry used e.g. by Notion and Google Workspace.

That way, when the user is signed in to the web app, the extension can use the same session to authenticate the user, so he doesn't have to sign in again. Also signing out from the extension will affect both platforms.

Cookies

When the user signs in to the web app through Supabase Auth, web app is setting the sb- cookie with the session data.

To make the session available also in the extension, you need to know the name of this cookie.

Usually, it follows the pattern sb-[project-id]-auth-token, where [project-id] is the id of your Supabase project (except local Docker development, where it's sb-[your-ip-address-first-segment]-auth-token).

You can find your cookie name in Cookies tab in the browser's developer tools (remember to be logged in to the app to check it):

Supabase cookie

Don't worry if it's splitted into multiple cookies (like on the image above) and encrypted. TurboStarter comes with pre-built solution to get and parse the session cookie value from the browser correctly.

Then, set it as environment variable in the extension:

apps/extension/.env.local
PLASMO_PUBLIC_AUTH_COOKIE_NAME="sb-..."

Remember to check the production cookie name, when you're doing a production build to ensure that your extension will read the correct user's cookie.

Also, to enable your extension to read the cookie, you need to set the cookies permission in the package.json under manifest.permissions field:

"permissions": [
  "cookies"
]

And to read the cookie from your app url, you need to set host_permissions, which will include your app url:

"host_permissions": [
  "http://localhost/*",
  "https://your-app-url.com/*"
]

Then you would be able to read the cookie value using chrome.cookies API.

Avoid "<all_urls>"

Avoid using <all_urls> in host_permissions. It affects all urls and may cause security issues, as well as a rejection from the destination store.

Reading session

You don't need to worry about reading, parsing or validating the session cookie. TurboStarter comes with a pre-built solution to get and parse the session cookie value from the browser correctly using chrome.cookies API (of course, it requires the steps above to be completed before).

We're doing it inside background service worker of the extension, you can find the code in apps/extension/src/app/background/messages/session.ts.

After parsing and validating that the cookie is valid, we're setting it directly on Supabase instance, so it's automatically accessible everywhere (e.g. can be used to authorize API requests).

To get session details in your extension code (e.g. inside popup window), we can leverage messaging system and @tanstack/react-query integration to send a message to the background service worker and receive the response with session details:

user.tsx
const User = () => {
  const { data, isLoading } = useQuery({
    queryKey: ["session"],
    queryFn: () =>
      sendToBackground<
        {
          type: typeof SESSION_MESSAGE_TYPE.GET;
        },
        {
          session: Session | null;
        }
      >({
        name: "session",
        body: { type: SESSION_MESSAGE_TYPE.GET },
      }),
  });
 
  if (isLoading) {
    return <p>Loading...</p>;
  }
 
  /* do something with the session data... */
  return <p>{data?.session?.user?.email}</p>;
};

That's how you can access user details right in your extension.

It's fully type-safe!

By leveraging TurboStarter architecture and passing correct types to the query (sendToBackground) we got a fully type-safe messaging system that we can use to communicate between different parts of the extension.

Read more about messaging

Signing out

Signing out from the extension also involves sending a message to the background service worker to delete the auth cookie from the browser:

logout.tsx
export const Logout = () => {
  const queryClient = useQueryClient();
  const { mutate } = useMutation({
    mutationFn: () =>
      sendToBackground({
        name: "session",
        body: { type: SESSION_MESSAGE_TYPE.DELETE },
      }),
    onSuccess: () => {
      void queryClient.invalidateQueries({ queryKey: ["session"] });
    },
  });
 
  return <button onClick={() => mutate()}>Log out</button>;
};

We're also invalidating the session query in the extension to update the UI and show the user as logged out.

This will sign out the user from the web app as well

As web app is using the same session cookie, the user will be signed out from the web app as well. This is intentional, as your extension will most probably serves as an add-on for the web app and it doesn't make sense to keep the user signed in there if the extension is not used.

Sign out

Last updated on

On this page

Ship your startup everywhere. In minutes.Get TurboStarter