Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to share local storage auth token from my site to my WebExtension?

I have a bookmarking firefox/chrome WebExtension (using the standard popup, content and background scripts). My api servers have a /login route that returns a JSON Web Token and the web app stores that in its local storage. I have full control over the extension, api, and web apps.

The barefoot way to do this is to have users log in through the popup and save the auth token in the background.js to the WebExtension's local storage. But I would really like to only ask the user to authenticate on my site and have that same auth apply to the extension as well.

Is there a way to share the auth token? I see Pocket and a lot of others doing this, but I'm not sure how.

like image 484
user Avatar asked Jun 15 '17 05:06

user


People also ask

How do I store access tokens?

Most guidelines, while advising against storing access tokens in the session or local storage, recommend the use of session cookies. However, we can use session cookies only with the domain that sets the cookie. Another popular suggestion is to store access tokens in the browser's memory.

How do I get JWT token from localStorage?

When the client logs in to the server, server gives token and saves it to the client localStorage (or sessionStorage ). Whenever the client calls an api which can be accessed only with the token, client retrieves the token back from the localStorage , and send that token with the authorization header ( req. headers.

How do I get discord token from local storage?

You can also use the shortcut Ctrl+Shift+M. Right-click the value on the right side, select edit value, then copy it. That's it! You now have your Discord token.


1 Answers

You could store the token as a cookie. Cookies work like localStorage, but with the extra that the're also by default wrapped into every HTTP request to the server. And here comes the trick. Chrome Extension can gain access to HTTP requests, with the use of webRequest API. Thus it can take a peek into the request headers and know your cookies. Having that web token as a cookie makes it available to the extension.

But still you need to wait for your website to be opened by the user, to have HTTP requests flowing and ready to be peeked at, right? Not really. You can make make an ajax request directly from the extension.

Here's to illustrate how the whole thing would work:

manifest:

"permissions": [
          "webRequest",
          "webRequestBlocking",
          "*://*.my_site.com/*"
        ]

Background page:

function callback (details) {
    //
    token = func_extract_token_from_headers(details.requestHeaders);

    chrome.webRequest.onBeforeSendHeaders.removeListener(callback); 

    return {cancel: false} //     set to true to prevent the request 
                           //   from reaching  the server
}
chrome.webRequest.onBeforeSendHeaders.addListener (callback,
        {urls: ["http://www.my_site.com/*", "https://www.my_site.com/*"]},
        ["blocking", "requestHeaders"]);


var xurl = "https://www.my_site.com/";
var xhr = new XMLHttpRequest();
xhr.open("GET", xurl, true);
xhr.send();

I should mention that there's a cleaner way to do it, but it currently does not work due to CSP--Content Secutiry Policiy. Opening the website in an iframe inside the background page, as mentioned by wOxxOm in comments, should work, with added CSP whitelisting of the website. This approach would also avoid prompting the user for credentials, and would be cleaner. Unfortunately it's not currently working

EDIT:

Sorry, I was wrong about my last claim: that iframes opening external pages are blocked in background pages. To display it in the background page(or popup for that matter), simply whitelist for CSP -- shown below.

Apart from the business of opening the page in an iframe, you need to communicate with it. That should be done using the window.postMessage API

Here's to exemplify how it all should come together:

Manifest:

// Whitelist your website
    "content_security_policy": "script-src 'self' https://my_site.com/; object-src 'self'"
// Have the background declared as html
  "background": { "page": "background.html"}

Background:

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  if(event.origin == "https://my_site.com"); //   you may want to check the 
                                             // origin to be your site 
  chrome.storage.storage.local.set({'auth_token': event.data});  // the token
}

iframe = document.createElement('iframe');
iframe.src = "https://my_site.com/";
// Have a div ready to place iframe in
document.getElementById('div').appendChild(iframe);

iframe.contentWindow.postMessage("give_token", "https://my_site.com")

The web page:

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  if(event.origin == "your_extension_id_aeiou12345");
     event.source.postMessage(''+localStorage.auth_token, event.origin);
}

EDIT:

Also, to have the website display in an iframe, make sure the X-frame-options response header is not set to a blocking value. You can either remove it, or set it to a non-blocking value, or white-list the url of the extension.

like image 167
kundrata Avatar answered Sep 19 '22 06:09

kundrata