Chrome Extension

View on Github

Chrome Extension

Community maintained

This tutorial demonstrates how to use the Auth0-Chrome SDK to add authentication and authorization to your Chrome extension. We recommend you to Log in to follow this quickstart with examples configured for your account.

I want to explore a sample app

2 minutes

Get a sample configured with your account settings or check it on Github.

View on Github
System requirements: auth0-chrome 0.1.2 | jwt-decode 2.1.0

New to Auth? Learn How Auth0 works, how it integrates with Native Applications and which protocol it uses.

Configure Auth0

Get Your Application Keys

When you signed up for Auth0, a new application was created for you, or you could have created a new one.

Your will need some details about that application to communicate with Auth0. You can get these details from the Application Settings section in the Auth0 dashboard.

You need the following information:

  • Client ID
  • Domain

If you download the sample from the top of this page these details are filled out for you.

If you have more than one application in your account, the sample comes with the values for your Default App.

App Dashboard

Install the Dependencies

The tutorial is based on a sample application which uses Universal Login and Chrome's launchWebAuthFlow.

Install auth0-chrome and jwt-decode with npm. The jwt-decode library is useful for decoding JSON Web Tokens and will be used to check the expiry time in this example.

npm install auth0-chrome jwt-decode --save

The dist folder of Auth0Chrome contains a webpack bundle for the package, including a minified version.

Configure your manifest.json file to run the auth0chrome script, along with an env.js and main.js script for your project. The default_popup should be set to a file called browser_action.html which will be used to provide a view to the popup.

{
  ...
  "browser_action": {
    "default_title": "Auth0",
    "default_popup": "src/browser_action/browser_action.html"
  },
  "background": {
    "scripts": [
      "./env.js",
      "node_modules/auth0-chrome/dist/auth0chrome.min.js",
      "src/main.js"
    ],
    "persistent": false
  },
  "permissions": [
    "identity",
    "notifications"
  ]
}

Integrate Auth0 in your Application

The client ID and domain for your application are used to connect to Auth0 and these will be required when instantiating Auth0Chrome. Create an env.js file and populate it with your application keys. Alternatively, you can pass these keys to the Auth0Chrome constructor directly.

// env.js

window.env = {
  AUTH0_DOMAIN: 'YOUR_AUTH0_DOMAIN',
  AUTH0_CLIENT_ID: 'YOUR_CLIENT_ID',
};

When downloading the sample project above, these values will come prepopulated for you.

Create the Main Popup

Create a browser_action.html file in src/browser_action and provide a view for your extension's popup. In this example the view has controls for allowing the user to log in and log out, as well as an area for displaying the user's profile after authentication.

<!-- src/browser_action/browser_action.html -->
...
<body>
  <div id="mainPopup">
    <div class="profile hidden">
      <div class="picture"></div>
      <div class="floater-profile">
        <div class="floater-background"></div>
        <div class="user-info">
          <h5 class="nickname"></h5>
          <h5 class="name"></h5>
        </div>
        <hr />
        <button class="btn btn-danger logout-button">Log Out</button>
      </div>
    </div>
    <div class="loading hidden">
      <div class="loading-bar"></div>
      <div class="loading-bar"></div>
      <div class="loading-bar"></div>
      <div class="loading-bar"></div>
    </div>
    <div class="default">
      <div class="text-center">
        <h3>Chrome Demo</h1>
        <button class="btn btn-success login-button">Log In With Auth0</button>
        <p class="caption">Press the Log In button above to log in.</p>
      </div>
    </div>
  </div>
  <script src="../../env.js"></script>
  <script src="./browser_action.js"></script>
  <script src="../../node_modules/jwt-decode/build/jwt-decode.js"></script>
</body>

The jwt-decode library is included within a script tag, as is a browser_action.js file. It's the browser_action.js file that will be used to control the view.

For this example, document.querySelector and document.querySelectorAll are used as a minimal way to mimic jQuery. Keep in mind that the specific technologies used to power the Chrome extension are at your discretion.

At a minimum, the Chrome extension needs to have views and logic to handle two cases: when the user is authenticated and when they are not. JWT authentication is stateless by nature, so the best indication we have that the user is authenticated is whether they have an unexpired token saved.

When the user is authenticated, a profile area should be displayed. When they aren't authenticated (they don't have a JWT or it becomes expired), the "Log In" button should be shown.

// src/browser_action/browser_action.js

function isLoggedIn(token) {
  // The user is logged in if their token isn't expired
  return jwt_decode(token).exp > Date.now() / 1000;
}

function logout() {
  // Remove the idToken from storage
  localStorage.clear();
  main();
}

// Minimal jQuery
const $$ = document.querySelectorAll.bind(document);
const $  = document.querySelector.bind(document);


function renderProfileView(authResult) {
  $('.default').classList.add('hidden');
  $('.loading').classList.remove('hidden');
  fetch(`https://${env.AUTH0_DOMAIN}/userinfo`, {
    headers: {
      'Authorization': `Bearer ${authResult.access_token}`
    }
  }).then(resp => resp.json()).then((profile) => {
    ['picture', 'name', 'nickname'].forEach((key) => {

       const element = $('.' +  key);
       if( element.nodeName === 'DIV' ) {
         element.style.backgroundImage = 'url(' + profile[key] + ')';
         return;
       }

       element.textContent = profile[key];
    });
    $('.loading').classList.add('hidden');
    $('.profile').classList.remove('hidden');
    $('.logout-button').addEventListener('click', logout);
  }).catch(logout);
}


function renderDefaultView() {
  $('.default').classList.remove('hidden');
  $('.profile').classList.add('hidden');
  $('.loading').classList.add('hidden');

  $('.login-button').addEventListener('click', () => {
    $('.default').classList.add('hidden');
    $('.loading').classList.remove('hidden');
    chrome.runtime.sendMessage({
      type: "authenticate"
    });
  });
}

function main () {
  const authResult = JSON.parse(localStorage.authResult || '{}');
  const token = authResult.id_token;
  if (token && isLoggedIn(token)) {
    renderProfileView(authResult);
  } else {
    renderDefaultView();
  }
}

document.addEventListener('DOMContentLoaded', main);

Two functions are provided to handle the scenarios described above. The renderProfileView function fetches the user's profile from Auth0's API at the /userinfo endpoint and shows the profile in the popup. The renderDefaultView function displays the Log In button and emits a message to trigger the authentication flow when clicked. Note that the user's Access Token is attached as an Authorization header in the call to the /userinfo endpoint.

The main function takes the authResult object saved in local storage and renders the profile view if the user's ID Token is unexpired, or the default view if it is expired.

popup

Initiate the Authentication Flow

The browser_action.js file controls the popup view and responds to button clicks, but the logic for the authentication flow still needs to be implemented.

Create a main.js file in the src directory and set it up to listen for the authenticate message that is emitted when the Log In button is clicked.

// src/main.js

chrome.runtime.onMessage.addListener(function (event) {
  if (event.type === 'authenticate') {

    // scope
    //  - openid if you want an ID Token returned
    //  - offline_access if you want a Refresh Token returned
    // device
    //  - required if requesting the offline_access scope.
    let options = {
      scope: 'openid offline_access',
      device: 'chrome-extension'
    };

    new Auth0Chrome(env.AUTH0_DOMAIN, env.AUTH0_CLIENT_ID)
      .authenticate(options)
      .then(function (authResult) {
        localStorage.authResult = JSON.stringify(authResult);
        chrome.notifications.create({
          type: 'basic',
          iconUrl: 'icons/icon128.png',
          title: 'Login Successful',
          message: 'You can use the app now'
        });
      }).catch(function (err) {
        chrome.notifications.create({
          type: 'basic',
          title: 'Login Failed',
          message: err.message,
          iconUrl: 'icons/icon128.png'
        });
      });
  }
});

When the authenticate message is received, an Auth0Chrome instance is created and its authenticate method is called, which opens a new window showing Auth0's hosted Lock.

The Auth0Chrome constructor takes the domain and client ID for your application, and the authenticate method takes an options object which allows you to customize the authentication flow. The authenticate method returns a promise and the result from the authentication process can be retrieved when it resolves. In this example, the result is saved in local storage immediately for future use and a Chrome notification is created to let the user know they have successfully logged in.

hosted-lock

Configure Auth0 Application Settings

Chrome extensions are packaged as .crx files for distribution but may be loaded "unpacked" for development. For more information on how to load an unpacked extension, see the Chrome extension docs.

When loading your application as an unpacked extension, a unique ID will be generated for it. In your application settings, you must whitelist your callback URL (the URL that Auth0 will return to once authentication is complete) and the allowed origin URL.

In the Allowed Callback URLs section, whitelist your callback URL.

https://<YOUR_EXTENSION_ID>.chromiumapp.org/auth0

In the Allowed Origins (CORS) section, whitelist your chrome extension as an origin.

chrome-extension://<YOUR_EXTENSION_ID>

Once the extension is published in the Chrome Web Store the Callback URL and the CORS origins used for development must be changed.

Use Auth0 for FREECreate free Account