Okta SignIn widget that renders the new login/auth/recovery flows
JavaScript CSS TypeScript Smarty Shell HTML
Switch branches/tags
Clone or download
gowthamidommety-okta 🐛 Prevents XSS when hovering over help icons (#495)
Escapes vendorName in tooltip text

Resolves: OKTA-175902
Latest commit f027b57 Jul 16, 2018
Permalink
Failed to load latest commit information.
.github 📝 Adds issue template for Okta Sign-In Widget repo (#469) Jun 1, 2018
assets 🌱 UX Improvements for password toggle (#489) Jul 5, 2018
buildtools Blacklist modules (#497) Jul 13, 2018
packages/@okta 🌱 UX Improvements for password toggle (#489) Jul 5, 2018
scripts ⬆️ Use Node 8 (#462) May 22, 2018
src 🐛 Prevents XSS when hovering over help icons (#495) Jul 16, 2018
test 🐛 Prevents XSS when hovering over help icons (#495) Jul 16, 2018
.eslintrc Adds dev logging for all dev builds (#452) May 22, 2018
.gitignore Moves private modules to packages, and uses package-lock.json (#260) Jul 12, 2017
.npmignore Moves private modules to packages, and uses package-lock.json (#260) Jul 12, 2017
.scss-lint.yml Fixed scss-lint errors Feb 8, 2016
.travis.yml ✅ Add okta-react tests (#372) Jan 3, 2018
CHANGELOG.md Added CI scripts, and created a version checking file Feb 8, 2016
CONTRIBUTING.md 📝 Add CONTRIBUTING.md (#132) Oct 26, 2016
Gemfile Fixed scss-lint errors Feb 8, 2016
Gemfile.lock Fixed scss-lint errors Feb 8, 2016
Gruntfile.js Adds dev logging for all dev builds (#452) May 22, 2018
LICENSE Update the license text in all the source code and the LICENCE/THIRD-… Mar 8, 2016
README.md 📝 Update readme (#491) Jul 5, 2018
THIRD-PARTY-NOTICES 👋 Goodbye $.cookie (#467) May 31, 2018
package-lock.json 👋 Goodbye $.cookie (#467) May 31, 2018
package.json ⬆️ Rev up version to handle @okta/ci-update-package upgrade (#496) Jul 10, 2018
pretest.js ✅ Add okta-angular tests (#374) Jan 3, 2018
webpack.common.config.js Blacklist modules (#497) Jul 13, 2018
webpack.dev.config.js Adds dev logging for all dev builds (#452) May 22, 2018
webpack.release.config.js 👋 Goodbye $.cookie (#467) May 31, 2018
webpack.test.config.js 🌱 Use default success/error handlers when not provided (#466) May 31, 2018

README.md

Build Status npm version

Okta Sign-In Widget

The Okta Sign-In Widget is a Javascript widget that provides a fully featured and customizable login experience which can be used to authenticate users on any website.

For a high level overview of the widget's features and authentication flows, check out our developer docs.

Contributors should read our contributing guidelines if they wish to contribute.

Table of Contents

Install

You can include the Sign-In Widget in your project either directly from the Okta CDN, or by packaging it with your app via our npm package, @okta/okta-signin-widget.

Using the Okta CDN

Loading our assets directly from the CDN is a good choice if you want an easy way to get started with the widget, and don't already have an existing build process that leverages npm for external dependencies.

To use the CDN, include links to the JS and CSS files in your HTML:

<!-- Latest CDN production Javascript and CSS: 2.9.0 -->
<script
  src="https://ok1static.oktacdn.com/assets/js/sdk/okta-signin-widget/2.9.0/js/okta-sign-in.min.js"
  type="text/javascript"></script>
<link
  href="https://ok1static.oktacdn.com/assets/js/sdk/okta-signin-widget/2.9.0/css/okta-sign-in.min.css"
  type="text/css"
  rel="stylesheet"/>

<!-- Theme file: Customize or replace this file if you want to override our default styles -->
<link
  href="https://ok1static.oktacdn.com/assets/js/sdk/okta-signin-widget/2.9.0/css/okta-theme.css"
  type="text/css"
  rel="stylesheet"/>

The okta-sign-in.min.js file will expose a global OktaSignIn object which can be used to bootstrap the widget:

var signIn = new OktaSignIn({/* configOptions */});

Using the npm module

Using our npm module is a good choice if:

  • You have a build system in place where you manage dependencies with npm
  • You do not want to load scripts directly from 3rd party sites

To install @okta/okta-signin-widget:

# Run this command in your project root folder.
npm install @okta/okta-signin-widget --save

The widget source files and assets will be installed to node_modules/@okta/okta-signin-widget/dist, and will have this directory structure:

node_modules/@okta/okta-signin-widget/dist/
  css/
    # Main CSS file for widget styles. Try not to override the classes in this
    # file when creating a custom theme - the classes/elements are subject to
    # change between releases
    okta-sign-in.min.css

    # Example theme that you can use as a template to create your own custom theme
    okta-theme.css

  # Base font and image files that are used in rendering the widget
  font/
  img/

  js/
    # CDN JS file that exports the OktaSignIn object in UMD format. This is
    # packaged with everything needed to run the widget, including 3rd party
    # vendor files.
    okta-sign-in.min.js

    # Main entry file that is used in the npm require(@okta/okta-signin-widget)
    # flow. This does not package 3rd party dependencies - these are pulled
    # down through `npm install` (which allows you to use your own version of
    # jquery, etc).
    okta-sign-in.entry.js

    # Development version of okta-sign-in.min.js. Equipped with helpful
    # console warning messages for common configuration errors.
    okta-sign-in.js

  # Localized strings that are used to display all text and labels in the
  # widget. Three output formats are included - json, jsonp, and properties
  labels/

  # Sass files that are used to generate the widget css. If you are already
  # using Sass in your project, you can include these helper files to make
  # generating your custom theme easier
  sass/

After running npm install:

  1. Copy the assets to a folder that will be distributed to your publicly hosted site. The folders you'll need to copy are css, font, img, js and labels.

  2. Instead of copying js and including it in your page as a global, you can require the Sign-In Widget in your build if you are using Webpack, Browserify or another module bundling system that understands the node_modules format.

    // Load the Sign-In Widget module
    var OktaSignIn = require('@okta/okta-signin-widget');
    
    // Use OktaSignIn
    var signIn = new OktaSignIn(/* configOptions */);

    Note: If you use Browserify to bundle your app, you'll need to use the --noparse option:

    browserify main.js \
    --noparse=$PWD/node_modules/@okta/okta-signin-widget/dist/js-okta-sign-in.entry.js \
    --outfile=bundle.js
    
  3. Make sure you include ES6 polyfills with your bundler if you need the broadest browser support. We recommend babel-polyfill.

API

new OktaSignIn(config)

Creates a new instance of the Sign-In Widget with the provided options. The widget has many config options. The only required option to get started is baseUrl, the base url for your Okta domain.

  • config - Options that are used to configure the widget
var signIn = new OktaSignIn(
  {
    baseUrl: 'https://{yourOktaDomain}'
  }
);

Note: https://{yourOktaDomain} can be any Okta organization. See Basic config options for more information.

renderEl(options, success, error)

Renders the widget to the DOM, and passes control back to your app through success and error callback functions when the user has entered a success or error state.

  • options
    • el - CSS selector which identifies the container element that the widget attaches to.
  • success (optional) - Function that is called when the user has completed an authentication flow. If an OpenID Connect redirect flow is used, this function can be omitted.
  • error (optional) - Function that is called when the widget has been initialized with invalid config options, or has entered a state it cannot recover from. If omitted, a default function is used to output errors to the console.
signIn.renderEl(
  // Assumes there is an empty element on the page with an id of 'osw-container'
  {el: '#osw-container'},

  function success(res) {
    // The properties in the response object depend on two factors:
    // 1. The type of authentication flow that has just completed, determined by res.status
    // 2. What type of token the widget is returning

    // The user has started the password recovery flow, and is on the confirmation
    // screen letting them know that an email is on the way.
    if (res.status === 'FORGOT_PASSWORD_EMAIL_SENT') {
      // Any followup action you want to take
      return;
    }

    // The user has started the unlock account flow, and is on the confirmation
    // screen letting them know that an email is on the way.
    if (res.status === 'UNLOCK_ACCOUNT_EMAIL_SENT') {
      // Any followup action you want to take
      return;
    }

    // The user has successfully completed the authentication flow
    if (res.status === 'SUCCESS') {

      // Handle success when the widget is not configured for OIDC

      if (res.type === 'SESSION_STEP_UP') {
        // Session step up response
        // If the widget is not configured for OIDC and the authentication type is SESSION_STEP_UP,
        // the response will contain user metadata and a stepUp object with the url of the resource
        // and a 'finish' function to navigate to that url
        console.log(res.user);
        console.log('Target resource url: ' + res.stepUp.url);
        res.stepUp.finish();
        return;
      } else {
        // If the widget is not configured for OIDC, the response will contain
        // user metadata and a sessionToken that can be converted to an Okta
        // session cookie:
        console.log(res.user);
        res.session.setCookieAndRedirect('https://acme.com/app');
        return;
      }


      // OIDC response

      // If the widget is configured for OIDC with a single responseType, the
      // response will be the token.
      // i.e. authParams.responseType = 'id_token':
      console.log(res.claims);
      signIn.tokenManager.add('my_id_token', res);

      // If the widget is configured for OIDC with multiple responseTypes, the
      // response will be an array of tokens:
      // i.e. authParams.responseType = ['id_token', 'token']
      signIn.tokenManager.add('my_id_token', res[0]);
      signIn.tokenManager.add('my_access_token', res[1]);

      return;
    }

  },

  function error(err) {
    // The widget will handle most types of errors - for example, if the user
    // enters an invalid password or there are issues authenticating.
    //
    // This function is invoked with errors the widget cannot recover from:
    // 1. Known errors: CONFIG_ERROR, UNSUPPORTED_BROWSER_ERROR, OAUTH_ERROR
    // 2. Uncaught exceptions
  }
);

hide

Hide the widget, but keep the widget in the DOM.

signIn.hide();

show

Show the widget if hidden.

signIn.show();

remove

Remove the widget from the DOM entirely.

signIn.remove();

on(event, callback[, context])

Subscribe to an event published by the widget.

  • event - Event to subscribe to
  • callback - Function to call when the event is triggered
  • context - Optional context to bind the callback to
signIn.on('pageRendered', function (data) {
  console.log(data);
});

off([event, callback])

Unsubscribe from widget events. If no callback is provided, unsubscribes all listeners from the event.

  • event - Optional event to unsubscribe from
  • callback - Optional callback that was used to subscribe to the event
// Unsubscribe all listeners from all events
signIn.off();

// Unsubscribe all listeners that have been registered to the 'pageRendered' event
signIn.off('pageRendered');

// Unsubscribe the onPageRendered listener from the 'pageRendered' event
signIn.off('pageRendered', onPageRendered);

session.get(callback)

Gets the active session, or returns {status:inactive} on error or no active session.

  • callback - Function that is called with the session once the request has completed.
signIn.session.get(function (res) {
  // Session exists, show logged in state.
  if (res.status === 'ACTIVE') {
    // showApp()
  }
  // No session, or error retrieving the session. Render the Sign-In Widget.
  else if (res.status === 'INACTIVE') {
    signIn.renderEl({
        el: '#osw-container'
      },
      function success(res) {
        // showApp() if res.status === 'SUCCESS'
      },
      function error(err) {
        // handleError(err)
      }
    );
  }
});

session.refresh(callback)

Refresh the current session by extending its lifetime. This can be used as a keep-alive operation.

  • callback - Function that is called after the refresh request has completed.
signIn.session.refresh(function (res) {
  if (res.status === 'ACTIVE') {
    // The session now has an extended lifetime
  }
  else if (res.status === 'INACTIVE') {
    // There is no current session, render the Sign-In Widget
  }
});

session.close(callback)

Signs the user out of their current Okta session.

  • callback - Function that is called once the session has been closed. If there is an error, it will be passed to the callback function.
signIn.session.close(function (err) {
  if (err) {
    // The user has not been logged out, perform some error handling here.
    return;
  }
  // The user is now logged out. Render the Sign-In Widget.
});

OIDC token.hasTokensInUrl()

Synchronous method to check for access or ID Tokens in the url. This is used when authParams.display = 'page'. Returns true if there are tokens, and false if the redirect flow has not taken place yet.

// For an extended example, look at token.parseTokensFromUrl
if (signIn.token.hasTokensInUrl()) {
  // The user has just successfully completed a redirect
}
else {
  // There are no tokens in the URL, render the Sign-In Widget.
}

OIDC token.parseTokensFromUrl(success, error)

Parses the access or ID Tokens from the url after a successful authentication redirect. This is used when authParams.display = 'page'.

  • success - Function that is called after the tokens have been parsed and validated
  • error - Function that is called if an error occurs while trying to parse or validate the tokens
var signIn = new OktaSignIn({
  baseUrl: 'https://{yourOktaDomain}',
  clientId: '{{myClientId}}',
  redirectUri: '{{redirectUri configured in OIDC app}}',
  authParams: {
    responseType: 'id_token',
    // `display: page` will initiate the OAuth2 page redirect flow
    display: 'page'
  },
  idps: [
    {
      type: 'FACEBOOK',
      id: '{{facebook appId}}'
    }
  ]
});

// The user has just landed on our login form, and has not yet authenticated
// with a Social Auth IDP.
if (!signIn.token.hasTokensInUrl()) {
  signIn.renderEl({el: '#osw-container'});
}

// The user has redirected back after authenticating and has their access or
// ID Token in the URL.
else {
  signIn.token.parseTokensFromUrl(
    function success(res) {
      signIn.tokenManager.add('my_id_token', res);
    },
    function error(err) {
      // handleError(err);
    }
  );
}

OIDC tokenManager.add(key, token)

After receiving an access_token or id_token, add it to the tokenManager to manage token expiration and refresh operations. When a token is added to the tokenManager, it is automatically refreshed when it expires.

  • key - Unique key to store the token in the tokenManager. This is used later when you want to get, delete, or refresh the token.
  • token - Token object that will be added
// Example showing a success callback when authParams.responseType = 'id_token'
signIn.renderEl({
    el: '#osw-container'
  },
  function (res) {
    if (res.status !== 'SUCCESS') {
      return;
    }

    // When specifying authParams.responseType as 'id_token' or 'token', the
    // response is the token itself
    signIn.tokenManager.add('my_id_token', res);
  }
);

OIDC tokenManager.get(key)

Get a token that you have previously added to the tokenManager with the given key.

  • key - Key for the token you want to get
var token = signIn.tokenManager.get('my_id_token');

OIDC tokenManager.remove(key)

Remove a token from the tokenManager with the given key.

  • key - Key for the token you want to remove
signIn.tokenManager.remove('my_id_token');

OIDC tokenManager.clear()

Remove all tokens from the tokenManager.

signIn.tokenManager.clear();

OIDC tokenManager.refresh(key)

Manually refresh a token before it expires.

  • key - Key for the token you want to refresh
// Because the refresh() method is async, you can wait for it to complete
// by using the returned Promise:
signIn.tokenManager.refresh('my_id_token')
.then(function (newToken) {
  // doSomethingWith(newToken);
});

// Alternatively, you can subscribe to the 'refreshed' event:
signIn.tokenManager.on('refreshed', function (key, newToken, oldToken) {
  // doSomethingWith(newToken);
});
signIn.tokenManager.refresh('my_id_token');

OIDC tokenManager.on(event, callback[, context])

Subscribe to an event published by the tokenManager.

  • event - Event to subscribe to. Possible events are expired, error, and refreshed.
  • callback - Function to call when the event is triggered
  • context - Optional context to bind the callback to
signIn.tokenManager.on('expired', function (key, expiredToken) {
  console.log('Token with key', key, ' has expired:');
  console.log(expiredToken);
});

signIn.tokenManager.on('error', function (err) {
  console.log('TokenManager error:', err);
});

signIn.tokenManager.on('refreshed', function (key, newToken, oldToken) {
  console.log('Token with key', key, 'has been refreshed');
  console.log('Old token:', oldToken);
  console.log('New token:', newToken);
});

OIDC tokenManager.off(event[, callback])

Unsubscribe from tokenManager events. If no callback is provided, unsubscribes all listeners from the event.

  • event - Event to unsubscribe from
  • callback - Optional callback that was used to subscribe to the event
signIn.tokenManager.off('refreshed');
signIn.tokenManager.off('refreshed', myRefreshedCallback);

Configuration

The only required configuration option is baseUrl. All others are optional.

// Basic example
var config = {
  baseUrl: 'https://{yourOktaDomain}',
  logo: '/path/to/logo.png',
  helpSupportNumber: '(123) 456-7890',
  language: 'en',
  i18n: {
    en: {
      'primaryauth.title': 'Sign in to Acme'
    }
  },
  helpLinks: {
    help: 'https://acme.com/help'
  }
};

var signIn = new OktaSignIn(config);

Basic config options

  • baseUrl: The base URL for your Okta organization

    // Production org with subdomain "acme"
    baseUrl: 'https://acme.okta.com'
    
    // Can also target oktapreview and okta-emea, i.e.
    baseUrl: 'https://acme.oktapreview.com'
  • logo: Local path or URL to a logo image that is displayed at the top of the Sign-In Widget

    // Hosted on the same origin
    logo: '/img/logo.png'
    
    // Can also be a full url
    logo: 'https://acme.com/img/logo.png'
  • helpSupportNumber: Support phone number that is displayed in the Password Reset and Unlock Account flows. If no number is provided, no support screen is shown to the user.

    // Can be any format - there are no formatting checks
    helpSupportNumber: '(123) 456-7890'

Username and password

  • username: Prefills the username input with the provided username

    username: 'john@acme.com'
  • transformUsername: Transforms the username before sending requests with the username to Okta. This is useful when you have an internal mapping between what the user enters and their Okta username.

    // The callback function is passed two arguments:
    // 1) username: The name entered by the user
    // 2) operation: The type of operation the user is trying to perform:
    //      - PRIMARY_AUTH
    //      - FORGOT_PASSWORD
    //      - UNLOCK_ACCOUNT
    transformUsername: function (username, operation) {
      // This example will append the '@acme.com' domain if the user has
      // not entered it
      return username.indexOf('@acme.com') > -1
        ? username
        : username + '@acme.com';
    }
  • processCreds: Hook to handle the credentials before they are sent to Okta in the Primary Auth, Password Expiration, and Password Reset flows.

    If processCreds takes a single argument it will be executed as a synchronous hook:

    // Passed a creds object {username, password}
    processCreds: function (creds) {
      // This example demonstrates a partial integration with ChromeOS
      google.principal.add({
        token: creds.username,
        user: creds.username,
        passwordBytes: creds.password,
        keyType: 'KEY_TYPE_PASSWORD_PLAIN'
      });
    }

    If processCreds takes two arguments it will be executed as an asynchronous hook:

    // Passed a creds object {username, password} and a callback for further processing
    processCreds: function (creds, callback) {
      // This example demonstrates optional legacy form-based login
      $.ajax({
        method: "POST",
        url: "/logintype",
        data: {
          username : creds.username
        },
        success: function (logintype) {
          if (logintype == "LEGACY") {
            $('#legacyUser').val(creds.username);
            $('#legacyPassword').val(creds.password);
            $('#legacyLogonForm').submit();
          } else {
            callback();
          }
        }
      });
    }

Language and text

  • language: Set the language of the widget. If no language is specified, the widget will choose a language based on the user's browser preferences if it is supported, or defaults to en.

    // You can simply pass the languageCode as a string:
    language: 'ja'
    
    // Or, if you need to determine it dynamically, you can pass a
    // callback function:
    language: function (supportedLanguages, userLanguages) {
      // supportedLanguages is an array of languageCodes, i.e.:
      // ['cs', 'da', ...]
      //
      // userLanguages is an array of languageCodes that come from the user's
      // browser preferences
      return supportedLanguages[0];
    }

    Supported languages:

    • cs - Czech
    • da - Danish
    • de - German
    • el - Greek
    • en - English
    • es - Spanish
    • fi - Finnish
    • fr - French
    • hu - Hungarian
    • id - Indonesian
    • it - Italian
    • ja - Japanese
    • ko - Korean
    • ms - Malaysian
    • nl-NL - Dutch
    • pl - Polish
    • pt-BR - Portuguese (Brazil)
    • ro - Romanian
    • ru - Russian
    • sv - Swedish
    • th - Thai
    • tr - Turkish
    • uk - Ukrainian
    • zh-CN - Chinese (PRC)
    • zh-TW - Chinese (Taiwan)
  • i18n: Override the text in the widget. The full list of properties can be found in the login.properties and country.properties files.

    // The i18n object maps language codes to a hash of property keys ->
    // property values.
    i18n: {
      // Overriding English properties
      'en': {
        'primaryauth.title': 'Sign in to Acme',
        'primaryauth.username.placeholder': 'Your Acme Username'
      },
      // Overriding Japanese properties
      'ja': {
        'primaryauth.title': 'ACMEにサインイン',
        'primaryauth.username.placeholder': 'ACMEのユーザー名'
      }
    }
    
    // If you want to override any properties in the country.properties file,
    // you will need to prefix the name with "country.":
    i18n: {
      'en': {
        // login.properties keys do not have a special prefix
        'primaryAuth.title': 'Sign in to Acme',
    
        // country.properties keys are prefixed with 'country.'
        'country.AF': 'Afghanistan, edited',
        'country.AL': 'Albania, edited'
      }
    }
  • assets.baseUrl: Override the base url the widget pulls its language files from. The widget is only packaged with english text by default, and loads other languages on demand from the Okta CDN. If you want to serve the language files from your own servers, update this setting.

    // Loading the assets from a path on the current domain
    assets: {
      baseUrl: '/path/to/dist'
    },
    
    // Full urls work as well
    assets: {
      baseUrl: 'https://acme.com/assets/dist'
    }

    Note: The jsonp files can be accessed from the dist/labels/jsonp folder that is published in the npm module.

  • assets.rewrite: You can use this function to rewrite the asset path and filename. Use this function if you will host the asset files on your own host, and plan to change the path or filename of the assets. This is useful, for example, if you want to cachebust the files.

    assets: {
      // Note: baseUrl is still needed to set the base path
      baseUrl: '/path/to/dist',
    
      rewrite: function (assetPath) {
        // assetPath is relative to baseUrl
        // Example assetPath to load login for 'ja': "/labels/jsonp/login_ja.jsonp"
        return someCacheBustFunction(assetPath);
      }
    }

Links

You can override a link URL by setting the following config options. If you'd like to change the link text, use the i18n config option.

Help Links

Set the following config options to override the help link URLs on the Primary Auth page.

// An example that overrides all help links, and sets two custom links
helpLinks: {
  help: 'https://acme.com/help',
  forgotPassword: 'https://acme.com/forgot-password',
  unlock: 'https://acme.com/unlock-account',
  custom: [
    {
      text: 'What is Okta?',
      href: 'https://acme.com/what-is-okta'
    },
    {
      text: 'Acme Portal',
      href: 'https://acme.com'
    }
  ]
}
  • helpLinks.help - Custom link href for the "Help" link

  • helpLinks.forgotPassword - Custom link href for the "Forgot Password" link

  • helpLinks.unlock - Custom link href for the "Unlock Account" link. For this link to display, features.selfServiceUnlock must be set to true, and the self service unlock feature must be enabled in your admin settings.

  • helpLinks.custom - Array of custom link objects {text, href} that will be added to the "Need help signing in?" section.

Sign Out Link

Set the following config option to override the sign out link URL. If not provided, the widget will navigate to Primary Auth.

signOutLink: 'https://www.signmeout.com'

Buttons

You can add buttons to the Primary Auth page by setting the following config options.

Custom Buttons

You can add custom buttons underneath the login form on the primary auth page by setting the following config options. If you'd like to change the divider text, use the i18n config option.

// An example that adds a custom button underneath the login form on the primary auth page
customButtons: [{
  title: 'Click Me',
  className: 'btn-customAuth',
  click: function() {
    // clicking on the button navigates to another page
    window.location.href = 'http://www.example.com';
  }
}]
  • customButtons.title - String that is set as the button text

  • customButtons.className - Optional class that can be added to the button

  • customButtons.click - Function that is called when the button is clicked

Registration Button

You can add a registration link to the primary auth page by setting features.registration to true and by adding the following config options.

// An example that adds a registration button underneath the login form on the primary auth page
registration: {
  click: function() {
    window.location.href = 'https://acme.com/sign-up';
  }
}
  • registration.click - Function that is called when the registration button is clicked

Registration

⚠️ Beta feature: The registration feature is currently a Beta feature. This widget functionality won't work unless your Okta organization is part of the Beta program. For help, contact support@okta.com.

To add registration into your application, configure your Okta admin settings to allow users to self register into your app. Then, set features.registration in the widget. You can add additional configs under the registration key on the OktaSignIn object.

    var signIn = new OktaSignIn({
      baseUrl: 'https://{yourOktaDomain}',
      // If you are using version 2.8 or higher of the widget, clientId is not required while configuring
      // registration. Instead the widget relies on policy setup with Self Service Registration. For help
      // with setting up Self Service Registration contact support@okta.com. Registration should continue
      // to work with a clientId set and version 2.7 or lower of the widget.
      clientId: '{{myClientId}}', // REQUIRED (with version 2.7.0 or lower)
      registration: {
        parseSchema: function(schema, onSuccess, onFailure) {
           // handle parseSchema callback
           onSuccess(schema);
        },
        preSubmit: function (postData, onSuccess, onFailure) {
           // handle preSubmit callback
           onSuccess(postData);
        },
        postSubmit: function (response, onSuccess, onFailure) {
            // handle postsubmit callback
           onSuccess(response);
        }
      },
      features: {
        // Used to enable registration feature on the widget.
        // https://github.com/okta/okta-signin-widget#feature-flags
         registration: true // REQUIRED
      }
    });

Optional configuration:

  • parseSchema: Callback used to mold the JSON schema that comes back from the Okta API.

    // The callback function is passed 3 arguments: schema, onSuccess, onFailure
    // 1) schema: json schema returned from the API.
    // 2) onSuccess: success callback.
    // 3) onFailure: failure callback. Note: accepts an errorObject that can be used to show form level or field level errors.
    
    parseSchema: function (schema, onSuccess, onFailure) {
      // This example will add an additional field to the registration form
        schema.profileSchema.properties.address = {
          'type': 'string',
          'description': 'Street Address',
          'default': 'Enter your street address',
          'maxLength': 255
        };
        schema.profileSchema.fieldOrder.push('address');
        onSuccess(schema);
    }
  • preSubmit: Callback used primarily to modify the request parameters sent to the Okta API.

     // The callback function is passed 3 arguments: postData, onSuccess, onFailure
     // 1) postData: form data that will be posted to the registration API.
     // 2) onSuccess: success callback.
     // 3) onFailure: failure callback. Note: accepts a errorObject that can be used to show form level or field level errors.
    preSubmit: function (postData, onSuccess, onFailure) {
      // This example will add @companyname.com to the email if user fails to add it during registration
      if (postData.username.indexOf('@acme.com') > 1) {
        return postData.username;
      } else {
        return postData.username + '@acme.com';
      }
    }
  • postSubmit: Callback used to primarily get control and to modify the behavior post submission to registration API .

     // The callback function is passed 3 arguments: response, onSuccess, onFailure
     // 1) response: response returned from the API post registration.
     // 2) onSuccess: success callback.
     // 3) onFailure: failure callback. Note: accepts an errorObject that can be used to show form level 
     //    or field level errors.
    postSubmit: function (response, onSuccess, onFailure) {
      // In this example postSubmit callback is used to log the server response to the browser console before completing registration flow
      console.log(response);
      // call onSuccess to finish registration flow
      onSuccess(response);
    }
  • onFailure and ErrorObject: The onFailure callback accepts an error object that can be used to show a form level vs field level error on the registration form.

    Use the default error

    preSubmit: function (postData, onSuccess, onFailure) {
      // A Default form level error is shown if no error object is provided
      onFailure();
    }

    Use form level error

    preSubmit: function (postData, onSuccess, onFailure) {
     var error = {
       "errorSummary": "Custom form level error"
     };
     onFailure(error);
    }

    Use field level error

      preSubmit: function (postData, onSuccess, onFailure) {
        var error = {
            "errorSummary": "API Error",
            "errorCauses": [
                {
                    "errorSummary": "Custom field level error",
                    "reason": "registration.error.address",
                    "resource": "User",
                    "property": "address", //should match field name
                    "arguments": []
                }
            ]
        };
        onFailure(error);
     }

IdP Discovery

ℹ️ EA feature: The Identity Provider (IdP) Discovery feature is currently an EA feature.

IdP Discovery enables you to route users to different 3rd Party IdPs that are connected to your Okta Org. Users can federate back into the primary org after authenticating at the IdP.

To use IdP Discovery in your application, first ensure that the IDP_DISCOVERY feature flag is enabled for your Org and configure an identity provider routing policy in the Okta admin panel. Then, in the widget configuration, set features.idpDiscovery to true and add additional configs under the idpDiscovery key on the OktaSignIn object.

var signIn = new OktaSignIn({
  baseUrl: 'https://{yourOktaDomain}',
  ... ...
  idpDiscovery: {
    requestContext: '/a/app/request/context',
  },
  features: {
    idpDiscovery: true
  }
});
signIn.renderEl(
  {...},
  function (res) {
    if (res.status === 'IDP_DISCOVERY') {
      res.idpDiscovery.redirectToIdp('/a/app/request/context');
      return;
    }
  }
);

The IdP Discovery authentication flow in widget will be

  1. If a routing policy with a username/domain condition is configured, the widget will enter identifier first flow
  2. Otherwise, the widget will enter primary authentication flow.

For the identifier first flow,

  1. The widget will display an identifier first page for the user to enter an Okta userName to determine the IdP to be used for authentication.
  2. If the IdP is your Okta org, the widget will transition to the primary authentication flow.
  3. If the IdP is a 3rd party IdP or a different Okta org, the widget will invoke the success callback with response.status as IDP_DISCOVERY.

Additional configuration

  • idpDiscovery.requestContext: a context of that which the user is trying to access, such as the path of an app

Additions in the success callback

  • response.status is IDP_DISCOVERY when the authentication needs to be done agaist 3rd party IdP.
  • res.idpDiscovery.redirectToIdp is a function that is used for redirecting to relative path of the 3rd party IdP. This function takes one parameter which is the idpDiscovery.requestContext.

OpenID Connect

Options for the OpenID Connect authentication flow. This flow is required for social authentication, and requires OAuth 2.0 client registration with Okta. For instructions, see Social Authentication.

  • clientId: Client Id pre-registered with Okta for the OIDC authentication flow

    clientId: 'GHtf9iJdr60A9IYrR0jw'
  • redirectUri: The url that is redirected to when using authParams.display:page. This must be pre-registered as part of client registration. If no redirectUri is provided, defaults to the current origin.

    redirectUri: 'https://acme.com/oauth2/callback/home'
  • idps: External Identity Providers to use in OIDC authentication. Supported IDPs are GOOGLE, FACEBOOK, and LINKEDIN.

    idps: [
      {type: 'GOOGLE', id: '0oaaix1twko0jyKik0g4'}
      {type: 'FACEBOOK', id: '0oar25ZnMM5LrpY1O0g3'}
      {type: 'LINKEDIN', id: '0oaaix1twko0jyKik0g4'}
    ]
  • idpDisplay: Display order for External Identity Providers relative to the Okta login form. Defaults to SECONDARY.

    • PRIMARY - Display External IDP buttons above the Okta login form
    • SECONDARY - Display External IDP buttons below the Okta login form
    idpDisplay: 'PRIMARY'
  • oAuthTimeout: Timeout for OIDC authentication flow requests, in milliseconds. If the authentication flow takes longer than this timeout value, an error will be thrown and the flow will be cancelled. Defaults to 12000.

    oAuthTimeout: 300000 // 5 minutes
  • authParams.display: Specify how to display the authentication UI for External Identity Providers. Defaults to popup.

    • popup - Opens a popup to the authorization server when an External Identity Provider button is clicked. responseMode will be set to okta_post_message and cannot be overridden.

    • page - Redirect to the authorization server when an External Identity Provider button is clicked. If responseMode is not specified, it will default to query if responseType = 'code', and fragment for other values of responseType.

    // Redirects to authorization server when the IDP button is clicked, and
    // returns an access_token in the url hash
    authParams: {
      display: 'page',
      responseType: 'token'
    }
  • authParams.responseMode: Specify how the authorization response should be returned. You will generally not need to set this unless you want to override the default values for your authParams.display and authParams.responseType settings.

    • okta_post_message - Used when authParams.display = 'popup'. Uses postMessage to send the response from the popup to the origin window.

    • fragment - Default value when authParams.display = 'page' and authParams.responseType != 'code'. Returns the authorization response in the hash fragment of the URL after the authorization redirect.

    • query - Default value when authParams.display = 'page' and authParams.responseType = 'code'. Returns the authorization response in the query string of the URL after the authorization redirect.

    • form_post - Returns the authorization response as a form POST after the authorization redirect. Use this when authParams.display = page and you do not want the response returned in the URL.

    // Use form_post instead of query in the Authorization Code flow
    authParams: {
      display: 'page',
      responseType: 'code',
      responseMode: 'form_post'
    }
  • authParams.responseType: Specify the response type for OIDC authentication. Defaults to id_token.

    Valid response types are id_token, access_token, and code. Note that code goes through the Authorization Code flow, which requires the server to exchange the Authorization Code for tokens.

    // Specifying a single responseType
    authParams: {
      responseType: 'token'
    }
    
    // Use an array if specifying multiple response types - in this case,
    // the response will contain both an ID Token and an Access Token.
    authParams: {
      responseType: ['id_token', 'token']
    }
  • authParams.scopes: Specify what information to make available in the returned id_token or access_token. For OIDC, you must include openid as one of the scopes. Defaults to ['openid', 'email'].

    Valid OIDC scopes: openid, email, profile, address, phone

    authParams: {
      scopes: ['openid', 'email', 'profile', 'address', 'phone']
    }
  • authParams.state: Specify a state that will be validated in an OAuth response. This is usually only provided during redirect flows to obtain an authorization code. Defaults to a random string.

    authParams: {
      state: '8rFzn3MH5q'
    }
  • authParams.nonce: Specify a nonce that will be validated in an id_token. This is usually only provided during redirect flows to obtain an authorization code that will be exchanged for an id_token. Defaults to a random string.

    authParams: {
      nonce: '51GePTswrm'
    }
  • authParams.issuer: Specify a custom issuer to perform the OIDC flow. Defaults to the baseUrl.

    authParams: {
      issuer: 'https://{yourOktaDomain}/oauth2/default'
    }
  • authParams.authorizeUrl: Specify a custom authorizeUrl to perform the OIDC flow. Defaults to the issuer plus "/v1/authorize".

    authParams: {
      issuer: 'https://{yourOktaDomain}/oauth2/default',
      authorizeUrl: 'https://{yourOktaDomain}/oauth2/default/v1/authorize'
    }
  • authScheme: Authentication scheme for OIDC authentication. You will normally not need to override this value. Defaults to OAUTH2.

    authParams: {
      authScheme: 'OAUTH2'
    }

Bootstrapping from a recovery token

  • recoveryToken: Bootstrap the widget into continuing either the Forgot Password or Unlock Account flow after the recovery email has been sent to the user with the recoveryToken.

    recoveryToken: 'x0whAcR02i0leKtWMZVc'

Feature flags

Enable or disable widget functionality with the following options. Some of these features require additional configuration in your Okta admin settings.

// An example that enables the autoPush and multiOptionalFactorEnroll features
features: {
  autoPush: true,
  multiOptionalFactorEnroll: true
}
  • features.router - Set to true if you want the widget to update the navigation bar when it transitions between pages. This is useful if you want the user to maintain their current state when refreshing the page, but requires that your server can handle the widget url paths. Defaults to false.

  • features.rememberMe - Display a checkbox to enable "Remember me" functionality at login. Defaults to true.

  • features.autoPush - Display a checkbox to enable "Send push automatically" functionality in the MFA challenge flow. Defaults to false.

  • features.smsRecovery - Allow users with a configured mobile phone number to recover their password using an SMS message. Defaults to false.

  • features.callRecovery - Allow users with a configured mobile phone number to recover their password using a voice call. Defaults to false.

  • features.windowsVerify - Display instructions for enrolling a windows device with Okta Verify. Defaults to false.

  • features.selfServiceUnlock - Display the "Unlock Account" link to allow users to unlock their accounts. Defaults to false.

  • features.multiOptionalFactorEnroll - Allow users to enroll in multiple optional factors before finishing the authentication flow. Default behavior is to force enrollment of all required factors and skip optional factors. Defaults to false.

  • features.hideSignOutLinkInMFA - Hides the sign out link for MFA challenge. Defaults to false.

  • features.registration - Display the registration section in the primary auth page. Defaults to false.

  • features.idpDiscovery - Enable IdP Discovery. Defaults to false.

  • features.showPasswordToggleOnSignInPage - End users can now toggle visibility of their password on the Okta Sign-In page, allowing end users to check their password before they click Sign In. This helps prevent account lock outs caused by end users exceeding your org's permitted number of failed sign-in attempts. Note that passwords are visible for 30 seconds and then hidden automatically. Defaults to false.

Events

Events published by the widget. Subscribe to these events using on.

  • pageRendered - triggered when the widget transitions to a new page, and animations have finished.

    // Overriding the "Back to Sign In" click action on the Forgot Password page
    signIn.on('pageRendered', function (data) {
      if (data.page !== 'forgot-password') {
        return;
      }
      var backLink = document.getElementsByClassName('js-back')[0];
      backLink.addEventListener('click', function (e) {
        e.preventDefault();
        e.stopPropagation();
        // Custom link behavior
      });
    });

Browser Support

Need to know if the Sign-In Widget supports your browser requirements? Please see Platforms, Browser, and OS Support.

Developing the Sign-In Widget

Building the widget

  1. Clone this repo and navigate to the new okta-signin-widget folder.

    git clone https://github.com/okta/okta-signin-widget.git
    cd okta-signin-widget
  2. Install Bundler if you don't already have it, and then install our Ruby dependencies.

    gem install bundler
    bundle install
  3. Install our Node dependencies.

    npm install
  4. Create a .widgetrc file in the okta-signin-widget directory with an entry for baseUrl.

    {
      "widgetOptions": {
        "baseUrl": "https://{yourOktaDomain}"
      }
    }
  5. Build the widget, start a local connect server that hosts it, and launch a browser window with the widget running.

    npm start
  6. Finally, enable CORS support for our new server by following these instructions. You can now authenticate to Okta using your very own, customizable widget!

The .widgetrc config file

The .widgetrc file is a configuration file that saves your local widget settings.

Property Description
widgetOptions Config options that are passed to the widget on initialization.
serverPort The port the local server runs on. Defaults to 3000

Build and test commands

Command Description
npm start Build the widget, start the server, and open a browser window with the widget loaded
npm run build:dev Build an unminified version of the widget
npm run build:release Build a minified, uglified version of the widget (okta-sign-in.min.js) and a non-minified development version of the widget (okta-sign-in.js).
npm test Run unit tests
npm run lint Run jshint and scss linting tests