chrome-extension-boilerplate-react-vite icon indicating copy to clipboard operation
chrome-extension-boilerplate-react-vite copied to clipboard

How to sync web app authentication with chrome extension

Open zaidbren opened this issue 1 year ago • 5 comments

Hello everyone, I have been working on a project that involves users signing up on my main web app. The web app is created using Nextjs 14 with the new app router support and I used the next-auth to make the user sign in. Now I want to sync the authentication state between my web app and the Chrome extension, so for example, the user can authenticate on the main web app and when the user clicks on the Chrome extension on a separate tab, I want to make sure that the chrome extension shows based on the authenticated routes. It should also be able to make requests to the backend. How can I enable something like this, I tried finding tutorials online, but I have no help yet

Thank you :)

zaidbren avatar Jan 06 '24 21:01 zaidbren

Thank you for your contribution. We will check and reply to you as soon as possible.

github-actions[bot] avatar Jan 06 '24 21:01 github-actions[bot]

Here are a few ways to achieve this:

  • Externally Connectable (I personally use this): Use the Externally Connectable feature of Chrome Extensions. By defining specific domains in your manifest file, your web app can communicate with the extension using message passing. When a user authenticates on your web app, you can send a message to the extension to update its state. This approach is secure and provides a real-time solution to keep the extension in sync.
  • Content Script with LocalStorage Listener: Implement a content script that runs on your web app's domain. The script can listen for changes to localStorage or sessionStorage, where your authentication state is stored. When a change is detected, the content script can relay that information to the background script of the extension, thereby updating its state. This method relies on the authentication logic to save the auth state on localStorage.
  • WebSockets for Real-Time Sync: Implement a WebSocket connection in your Chrome extension that listens to a server endpoint. Whenever the user's authentication state changes on the server side (like through your main web app), the server can push the new state to the extension. This method provides real-time synchronization and works well for applications requiring immediate state updates. Your background service worker might die, add a heartbeat subscription to keep the connection alive. Chrome Docs

raynirola avatar Jan 07 '24 01:01 raynirola

Here are a few ways to achieve this:

  • Externally Connectable (I personally use this): Use the Externally Connectable feature of Chrome Extensions. By defining specific domains in your manifest file, your web app can communicate with the extension using message passing. When a user authenticates on your web app, you can send a message to the extension to update its state. This approach is secure and provides a real-time solution to keep the extension in sync.
  • Content Script with LocalStorage Listener: Implement a content script that runs on your web app's domain. The script can listen for changes to localStorage or sessionStorage, where your authentication state is stored. When a change is detected, the content script can relay that information to the background script of the extension, thereby updating its state. This method relies on the authentication logic to save the auth state on localStorage.
  • WebSockets for Real-Time Sync: Implement a WebSocket connection in your Chrome extension that listens to a server endpoint. Whenever the user's authentication state changes on the server side (like through your main web app), the server can push the new state to the extension. This method provides real-time synchronization and works well for applications requiring immediate state updates. Your background service worker might die, add a heartbeat subscription to keep the connection alive. Chrome Docs

Hi, can you share your solution , cause I try to sync the state , I found it does not work , not matter one of the extension or react logout , they can't sync the logout stsate , thank you so much

talpx0 avatar Jan 09 '24 03:01 talpx0

Hi, can you share your solution , cause I try to sync the state , I found it does not work , not matter one of the extension or react logout , they can't sync the logout stsate , thank you so much

Externally connectable:

// manifest.js

externally_connectable: {
  matches: ['*://*.yourdomain.com/*'],
  accepts_tls_channel_id: true,
}
// service worker

chrome.runtime.onMessageExternal.addListener(async (message, sender, sendResponse) => {
  if (message.type === 'logged-in') {
    console.dir(message);
    sendResponse({ message: 'OK' });
    return true;
  }

  if (message.type === 'logged-out') {
    console.dir(message);
    sendResponse({ message: 'OK' });
    return true;
  }
});
// Web

const user = { id: 1234, name: 'John Doe', token: 'somejwtstuff' };

export async function sendLoggedInMessageToExtension() {
  const res = await chrome.runtime.sendMessage(
    'your-extension-id',
    { type: 'logged-in', data: user },
    { includeTlsChannelId: true }
  );

  console.log(res);
}

raynirola avatar Jan 09 '24 07:01 raynirola

@raynirola Hello, Thank you so much for sharing the code, just a question, the web part, is that had to be the inside useEffect or it could be a server endpoint in nextjs? And can all this be done without having the web app opened on a tab?

Do we have to send messages everytime to our frontend web app in order to get data from the database etc.?

zaidbren avatar Jan 09 '24 07:01 zaidbren

Once i see this video: https://www.youtube.com/watch?v=dXem_TaH9To&t=529s

Maybe it explain sth for you.

I think safe and easy way to do it, is grab a cookie from your main page, and on your chrome extension, send request with this cookie for backend and check if user was authenticated.

This is good also when e.g session was expiring and the cookie disappear and you can handle logging out on plugin in one time.

PatrykKuniczak avatar Jan 10 '24 10:01 PatrykKuniczak

@PatrykKuniczak, Yes that's the approach I took, I basically saves a user with userid and session token in the database and that cookie on the frontend. Now that cookie would be received by the chrome extension on every request and it would be able to make request to the API routes :)

Thank you for answering

zaidbren avatar Jan 10 '24 14:01 zaidbren

@zaidbren If you want to look how to do it, let's look here: https://github.com/PatrykKuniczak/YT_Notifier/tree/main/nest-app

If you have any other question, feel free to reopen this issue :)

PatrykKuniczak avatar Jan 10 '24 14:01 PatrykKuniczak