Awesome
<!-- START GITHUB ONLY --><img src="https://aws1.discourse-cdn.com/standard14/uploads/oktadev/original/1X/0c6402653dfb70edc661d4976a43a46f33e5e919.png" align="right" width="256px"/>
<!-- END GITHUB ONLY --> <!-- links --> <!-- end links --> <!-- omit in toc -->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 and register users in web and mobile applications.
The widget is used on Okta's default signin page to start an Okta SSO session and set the Okta session cookie in the web browser. It can also perform an OIDC flow to easily integrate your web or mobile applications into the Okta platform.
A custom Okta-hosted signin page can be configured to use your organization's domain name and branding.
The widget can also be embedded directly into your organization's web or mobile applications for a seamless user experience.
See the Usage Guide for more information on how to get started using the Sign-in Widget.
<!-- TOC is generated using Markdown All in One -->- Okta Identity Engine
- Related SDKs
- Sample applications
- Usage Guide
- API Reference
- Configuration
- Events
- Building the Widget
- Browser support
- Contributing
Okta Identity Engine
The Okta Identity Engine (OIE) is a platform service that allows enterprises to build more flexible access experiences that are tailored to their organizational needs. The Okta Sign-in Widget supports OIE in all usage scenarios.
Note: Unless otherwise noted, this README assumes you are using Identity Engine. Information on using the widget with the Classic Engine can be found in this document
Related SDKs
The Sign-in Widget is self-contained and requires no other frameworks at runtime. However, there may be certain features your app needs such as token storage, renewal, or validation, which the widget does not provide.
These SDKs are fully compatible with the Okta Sign-in Widget and provide utilities to help integrate Okta authentication end-to-end in your own application.
Javascript
- okta-auth-js (Browser or NodeJS)
- okta-react
- okta-angular
- okta-vue
Java
.Net
Sample applications
Complete sample applications demonstrate usage of the Okta Sign-In Widget in both Okta-hosted and embedded scenarios.
- Javascript (Browser/SPA)
- Javascript (Express/NodeJS)
- React
- Angular
- Vue
- Asp.Net Core 2.x
- ASP.Net Core 3.x
- ASP.Net 4.x
- ASP.Net Webforms
- Golang
- Java/Spring Boot
- PHP
- Python/Flask
Usage Guide
There are several ways to use the Okta Sign-in Widget:
-
Okta provides a default sign-in page for your organization, hosted at your organization's Okta URL.
-
Okta supports an option to create a custom domain with a highly customizable Okta-hosted sign-in page.
-
You can embed the widget directly into your application.
Okta-hosted sign-in page (default)
Okta provides a sign-in page, available at your organization's URL, which allows the user to complete the entire authorization flow, start an SSO (Single Sign-On) session, and set the Okta session cookie in the web browser. You can customize this page with a background image and logo. By default, signing in on this page redirects the user to the Okta user dashboard.
The default Okta-hosted sign-in page can also authenticate a user in an OIDC application. Your app can redirect to a sign-in page to perform the authentication flow, after which Okta redirects the user back to the app callback. Okta provides SDKs in many languages to help construct the redirect URL and handle the login callback as part of the hosted flow.
Okta provides several complete sample applications which demonstrate how to use the Okta hosted flow.
Okta-hosted sign-in page (customizable)
Okta also provides a hosted sign-in page that can be customized so that it is available under a custom domain which is a subdomain of your company's top-level domain. Although the page is hosted by Okta, you can customize the template of this page in many powerful ways.
As far as your app is concerned, the customized widget behaves the same as the default Okta-hosted widget and you can use the same hosted flow.
Note: There will be a configuration object on the page which contains all required values and enabled features. You will most likely not need to modify this object. If you find that you do need to modify this configuration, take care not to overwrite or remove any required values.
Embedded (self-hosted)
For a completely seamless experience that allows for the highest level of customization, you can embed the Sign-In Widget directly into your application. This allows full use of the widget's configuration and API.
Using an embedded widget, client-side web and native apps can avoid the round-trip redirect of the hosted flow in many cases. See showSignIn.
Server-side web applications will receive OAuth tokens server-side, so they must handle a redirect callback. These apps should use showSignInAndRedirect.
You can embed the Sign-In Widget in your app by either including a script tag that pulls the widget from the Okta CDN or bundling the NPM module into your app.
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, don't already have an existing build process that leverages npm or yarn for external dependencies, or any other reason where you don't want to bundle the Sign-in Widget into your application.
The standard bundle (okta-sign-in.min.js
) includes support for both Classic Engine and the Identity Engine. It also includes a polyfill to ensure compatibility with older browsers such as IE11. If your application doesn't need to support IE11, you can include the no-polyfill
bundle instead to decrease the loading time for first-time users. The standalone polyfill
bundle can be conditionally included on pages to add support for older browsers only when necessary.
If your organization has upgraded to Identity Engine, the smaller oie
bundle can be used.
Bundle | File Name | Approx. Size | Classic Engine | Identity Engine | Polyfill | Notes |
---|---|---|---|---|---|---|
standard | okta-sign-in.min.js | 1.7 MB | :white_check_mark: | :white_check_mark: | :white_check_mark: | Standard bundle which includes everything |
no-polyfill | okta-sign-in.no-polyfill.min.js | 1.7 MB | :white_check_mark: | :white_check_mark: | Standard bundle without polyfill | |
oie | okta-sign-in.oie.min.js | 1.3 MB | :white_check_mark: | Smaller bundle for OIE enabled orgs | ||
classic | okta-sign-in.classic.min.js | 1.1 MB | :white_check_mark: | Smaller bundle for Classic Engine only | ||
polyfill | okta-sign-in.polyfill.min.js | 108KB | :white_check_mark: | Standalone polyfill bundle. Can be used along with a widget bundle that does not include the polyfill. |
To embed the Sign-in Widget via CDN, include links to the JS and CSS files in your HTML:
<!-- Latest CDN production Javascript and CSS -->
<script src="https://global.oktacdn.com/okta-signin-widget/7.25.1/js/okta-sign-in.min.js" type="text/javascript" integrity="sha384-8QHSy1n8imbyR7imair5z4njOEYiZZk5gqBOJYbbUN3W6HQwW3PZ9lYQiybespeW" crossorigin="anonymous"></script>
<link href="https://global.oktacdn.com/okta-signin-widget/7.25.1/css/okta-sign-in.min.css" type="text/css" rel="stylesheet" integrity="sha384-63aTBe2wMqzMRsDHNmlF/FreSWmf3p08BhUDoPlzVf3d+stbkfWtqmdyJ4He5m3m" crossorigin="anonymous" />
NOTE: The CDN URLs contain a version number. This number should be the same for both the Javascript and the CSS file and match a version on the releases page. We recommend using the latest widget version.
When using one of the bundles without the polyfill included, you may want to conditionally load the standalone polyfill bundle. The polyfill should be loaded before the widget bundle:
<!-- Polyfill for older browsers -->
<script src="https://global.oktacdn.com/okta-signin-widget/7.25.1/js/okta-sign-in.polyfill.min.js" type="text/javascript" integrity="sha384-QzQIGwIndxyBdHRQOwgjmQJLod6LRMchZyYg7RUq8FUECvPvreqauQhkU2FF9EGD" crossorigin="anonymous"></script>
<!-- Widget bundle for Okta Identity Engine -->
<script src="https://global.oktacdn.com/okta-signin-widget/7.25.1/js/okta-sign-in.oie.min.js" type="text/javascript" integrity="sha384-T4d68QBaFQ/b3kDy8qubuXDALwWgBRfP0JsfZsYRzZNlIXflVE2svwIHrPaivLyd" crossorigin="anonymous"></script>
<!-- CSS for widget -->
<link href="https://global.oktacdn.com/okta-signin-widget/7.25.1/css/okta-sign-in.min.css" type="text/css" rel="stylesheet" integrity="sha384-63aTBe2wMqzMRsDHNmlF/FreSWmf3p08BhUDoPlzVf3d+stbkfWtqmdyJ4He5m3m" crossorigin="anonymous" />
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 or yarn
- 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
# yarn
yarn add @okta/okta-signin-widget
# npm
npm install @okta/okta-signin-widget --save
This installs the latest version of the Sign-in Widget to your project's node_modules
directory.
NOTE: If you're using TypeScript, you'll need to enable synthetic imports in your tsconfig.json
.
{
...
"compilerOptions": {
"allowSyntheticDefaultImports": true,
...
}
}
Angular (TypeScript) projects require a simliar configuration, also in your tsconfig.json
{
...
"angularCompilerOptions": {
"allowSyntheticDefaultImports": true,
...
}
}
The widget source files and assets are installed to node_modules/@okta/okta-signin-widget/dist
, and have this directory structure:
node_modules/@okta/okta-signin-widget/dist/
├── css/
│ │ # Main CSS file for widget styles
│ └── okta-sign-in.min.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 and polyfills.
│ ├── okta-sign-in.min.js
| |
│ │ # CDN JS file bundled without polyfills.
│ ├── okta-sign-in.no-polyfill.min.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 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 installing:
-
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
andlabels
. -
Instead of copying the
js
directory 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 thenode_modules
format.// Load the Sign-In Widget module var OktaSignIn = require('@okta/okta-signin-widget'); // Use OktaSignIn var signIn = new OktaSignIn(/* configOptions */);
Source maps are provided as an external .map file. If you are using Webpack, these can be loaded using the source-map-loader plugin.
If you want to include widget styles in bundle using style-loader or mini-css-extract-plugin, use the following import:
import '@okta/okta-signin-widget/css/okta-sign-in.min.css';
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
-
Make sure you include ES6 polyfills with your bundler if you need to support IE11. The widget provides all needed polyfills through an export:
const polyfill = require('@okta/okta-signin-widget/polyfill');
or
import polyfill from '@okta/okta-signin-widget/polyfill';
Examples
These simple examples should help you get started with using the Sign-in Widget. For complete end-to-end solutions, check out our sample applications.
SPA Application
A Single Page Application (SPA) runs completely in the browser. SPA applications authenticate using client-side flows and store OAuth tokens in browser-based storage.
Note: See configuration for more information on these configuration values
var signIn = new OktaSignIn(
{
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
}
);
signIn.showSignIn({
// Assumes there is an empty element on the page with an id of 'osw-container'
el: '#osw-container'
}).then(function(res) {
// Most flows will not require any redirection. In these cases, tokens will be returned directly.
// res.tokens is an object
oktaSignIn.authClient.handleLoginRedirect(res.tokens);
}).catch(function(error) {
// This function is invoked with errors the widget cannot recover from:
// Known errors: CONFIG_ERROR, UNSUPPORTED_BROWSER_ERROR
});
Web Application
A web application runs primarily on the server. The widget, which executes client-side, will be embedded into an HTML page that includes a script block that configures and renders the widget. OAuth tokens will be received server-side on the application's login redirect callback.
Note: See configuration for more information on these configuration values
var signIn = new OktaSignIn(
{
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
state: '{{state passed from backend}}', // state can be any string, it will be passed on redirect callback
codeChallenge: '{{PKCE code challenge from backend}}', // PKCE is required for interaction code flow
}
);
// When the authorization flow is complete there will be a redirect to Okta.
// Okta's servers will process the information and then redirect back to your application's `redirectUri`
// If successful, an authorization code will exist in the URL as the "code" query parameter
// If unsuccesful, there will be an "error" query parameter in the URL
signIn.showSignInAndRedirect({
// Assumes there is an empty element on the page with an id of 'osw-container'
el: '#osw-container'
}).catch(function(error) {
// This function is invoked with errors the widget cannot recover from:
// Known errors: CONFIG_ERROR, UNSUPPORTED_BROWSER_ERROR
});
Flow
In addition to the default authentication flow, the widget supports several pre-defined flows, which allow you to provide single-purpose HTML pages for several common use-cases.
By default, the Okta Sign-In Widget will either proceed with a current flow or start a new authenticate flow. The flow
option allows bootstrapping the widget into a specific view such as register, unlock, or reset password. Supported flows:
- login
- signup
- resetPassword
- unlockAccount
Note: A particular flow can only work if the admin has configured the org to allow the required operations (example: if Profile Enrollment (User sign-up) in the admin console is not enabled, bootstrapping the widget with
flow: 'signup'
will result in an error)
// login.html
new OktaSignIn({
flow: 'login'
});
// signup.html
new OktaSignIn({
flow: 'signup'
});
// reset_password.html
new OktaSignIn({
flow: 'resetPassword'
});
// unlock_account.html
new OktaSignIn({
flow: 'unlockAccount'
});
Redirect Callbacks
A redirect callback occurs when your app is reloaded in the browser as part of a flow. During a redirect callback, the app is loaded at a specific URL path that you have defined in your Okta App configuration. Most callbacks can only be handled once and will produce an error if there is an attempt to handle it twice. Typically, the app will redirect itself to a well known or previously saved URL path after the callback logic has been handled to avoid errors on page reload.
Note: Most apps should be prepared to handle one or more redirect callbacks. Depending on how the App sign-on policy is configured, some SPA applications may be able to receive tokens without any redirect. However, logic will need to be added if the policy includes signing in with a Social / IDP provider or allows authentication or account recovery using email verification.
OAuth callback
The OAuth callback is the last step of the interaction code flow. On successful authentication, the browser is redirected to Okta with information to begin a new session. Okta's servers process the information and then redirect back to your application's redirectUri
. If successful, an interaction code is present in the URL as the interaction_code
query parameter. If unsuccessful, there is an error
and error_description
query parameters in the URL. Whether successful or not, the state
parameter, which was originally passed to the widget by your application, will also be returned on the redirect. This can be used by server-side web applications to match the callback with the correct user session.
All web applications will handle an OAuth callback. For SPA applications, in many cases the sign-on policy will not require a redirect and these applications can receive tokens directly from showSignIn. However, if the sign-on policy requires redirection for any reason (such as integration with a Social / IDP provider) SPA apps will need to handle an Oauth callback. For this reason we recommend that all SPA apps should be prepared to handle an OAuth callback.
Note: The widget does not handle an OAuth callback directly. Server-side web applications can use one of our SDKs to help with handling the callback. SPA applications can use the okta-auth-js SDK, which is included with the Sign-in Widget as the
authClient
property.
A SPA application can handle the OAuth callback client-side using the built-in authClient
:
// https://myapp.mycompany.com/login/callback?interaction_code=ABC&state=XYZ
if (signIn.authClient.isLoginRedirect()) {
await signIn.authClient.handleLoginRedirect();
}
Social/IDP callback
After signing in with a 3rd party IDP, the user is redirected back to the application's redirectUri
. If no further input is needed from the user, then this will be an OAuth callback containing an interaction_code
parameter. If further input is required, then the callback will contain an error
parameter with the value interaction_required
. In this case, the Sign-in Widget should be loaded again so that the flow can continue.
Both server-side web and SPA applications should look for the error
query parameter and, if the value is interaction_required
, they should render the widget again using the same configuration as the first render. The state
parameter will also be passed on the callback which can be used to match the request with the user's application session. The widget will automatically proceed with the transaction.
Email verify callback
Your application will need to implement an email verify callback if your sign-on policy uses Email Magic Link/OTP. After the user clicks the link in an email, they are redirected back to the application's email verify callback URI
. The query parameters passed to the application include state
and otp
. As with the Social/IDP callback, the widget should be rendered again using the same configuration. Additionally, the otp
should be passed to the widget's constructor.
Note: See configuration for more information on these configuration values
var signIn = new OktaSignIn(
{
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
state: '{{state from URL}}',
otp: '{{otp from URL}}'
}
);
API Reference
OktaSignIn
Creates a new instance of the Sign-In Widget with the provided options.
For applications using a customized Okta-hosted widget, there will be a configuration object on the page which contains all required values. You will most likely not need to modify this object.
For applications using an embedded widget, you will need to provide an OIDC configuration:
Note: See configuration for more information on these configuration values
var signIn = new OktaSignIn(
{
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
}
);
showSignIn
Renders the widget to the DOM. On success, the promise resolves. On error, the promise rejects. If the sign-on policy requires a redirect to Okta or another identity provider (IdP), the browser will redirect and the promise will not resolve. The responses and errors are the same as those for renderEl.
Note: This is the recommended way to render the widget for SPA applications. Server-side web apps should use the showSignInAndRedirect method instead.
showSignIn
accepts the same options as the widget constructor. Options passed to the method will override options from the constructor.
Note: See configuration for more information on these configuration values
var signIn = new OktaSignIn({
issuer: 'https://{yourOktaDomain}/oauth2/default'
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
});
oktaSignIn.showSignIn({
// Assumes there is an empty element on the page with an id of ‘osw-container’
el: ‘#osw-container’,
}).then(response => {
oktaSignIn.authClient.handleLoginRedirect(res.tokens);
}).catch(function(error) {
// This function is invoked with errors the widget cannot recover from:
// Known errors: CONFIG_ERROR, UNSUPPORTED_BROWSER_ERROR
console.log('login error', error);
});
showSignInAndRedirect
Renders the widget to the DOM. On successful authentication, the browser will be redirected to Okta with information to begin a new session. Okta's servers will process the information and then redirect back to your application's redirectUri
. If successful, an interaction code will exist in the URL as the interaction_code
query parameter. If unsuccessful, there will be error
and error_description
query parameters in the URL. Whether successful or not, the state
parameter which was passed to the widget will also be returned on redirect. This can be used by your server-side web application to match the callback with the correct user session.
showSignInAndRedirect
accepts the same options as the widget constructor. Options passed to the method will override options from the constructor.
Note: See configuration for more information on these configuration values
var signIn = new OktaSignIn({
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
state: '{{state passed from backend}}', // state can be any string, it will be passed on redirect callback
codeChallenge: '{{PKCE code challenge from backend}}', // PKCE is required for interaction code flow
});
signIn.showSignInAndRedirect({
// Assumes there is an empty element on the page with an id of 'osw-container'
el: '#osw-container'
}).catch(function(error) {
// This function is invoked with errors the widget cannot recover from:
// Known errors: CONFIG_ERROR, UNSUPPORTED_BROWSER_ERROR
});
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
Subscribe to an event published by the widget.
event
- Event to subscribe tocallback
- Function to call when the event is triggered
// Handle a 'ready' event using an onReady callback
signIn.on('ready', onReady);
off
Unsubscribe from widget events. If no callback is provided, unsubscribes all listeners from the event.
event
- Optional event to unsubscribe fromcallback
- 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 'ready' event
signIn.off('ready');
// Unsubscribe the onReady listener from the 'ready' event
signIn.off('ready', onReady);
authClient
Provides access to the underlying [@okta/okta-auth-js][] object used by the Sign-in Widget. All methods are documented in the API reference.
The authClient
is configured using values passed to the widget, such as clientId
, issuer
, redirectUri
, state
, and scopes
. Options which are not directly supported by the widget can be passed to AuthJS using the authParams
object.
The authClient
can also be created and configured outside the widget and passed to the widget as the authClient
option. If an authClient
option is passed, authParams
will be ignored.
Note: See configuration for more information on these configuration values
var authClient = new OktaAuth({
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{yourClientId}',
redirectUri: '{{redirectUri configured in OIDC app}}',
});
var config = {
baseUrl: 'https://{yourOktaDomain}',
authClient: authClient,
};
var signIn = new OktaSignIn(config);
// signIn.authClient === authClient
If no authClient
option is set, an instance will be created using the options passed to the widget and authParams
:
Note: When using the
authClient
configuration option, make sure to install and use the same version of@okta/okta-auth-js
as that used by the installed widget. This version can be found in thepackage.json
file of the installed widget.
var config = {
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{yourClientId}',
redirectUri: '{{redirectUri configured in OIDC app}}',
authParams: {
ignoreSignature: true
}
};
var signIn = new OktaSignIn(config);
// signIn.authClient.options.clientId === '{yourClientId}'
// signIn.authClient.options.ignoreSignature === true'
before
Adds an asynchronous hook function which will execute before a view is rendered.
Note: See configuration for more information on these configuration values
var config = {
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{yourClientId}',
redirectUri: '{{redirectUri configured in OIDC app}}',
};
var signIn = new OktaSignIn(config);
signIn.before('success-redirect', async () => {
// custom logic can go here. when the function resolves, execution will continue.
});
after
Note: This function is only supported when using the Okta Identity Engine
Adds an asynchronous hook function which will execute after a view is rendered.
Note: See configuration for more information on these configuration values
var config = {
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{yourClientId}',
redirectUri: '{{redirectUri configured in OIDC app}}',
};
var signIn = new OktaSignIn(config);
signIn.after('identify', async () => {
// custom logic can go here. when the function resolves, execution will continue.
});
Configuration
If you are using the default Okta-hosted signin page, all configuration is handled via the Customization
section of the Admin UI.
If you are using the custom Okta-hosted signin page, a configuration object is included on the page which contains all necessary values. You will probably not need to modify this object, but you may use this object as a starting point and add additional customizations.
For embedded widgets, you should set the issuer
, clientId
, and redirectUri
. By default, the widget will run on the Identity Engine using the interaction code flow. The widget can also run against the Classic Engine by setting the useClassicEngine option to true
. (See this document for more details on running in Classic Engine.
Basic config options
All embedded widgets should set these basic options: issuer
, clientId
, and redirectUri
.
Note: Okta-hosted widgets should not set these values.
issuer
The URL of the Authorization Server which will issue OAuth tokens to your application.
Note:
https://{yourOktaDomain}
can be any Okta organization. See our developer guide for help with finding your Okta domain.
Basic configuration using the "default" Custom Authorization Server:
var config = {
issuer: 'https://{yourOktaDomain}/oauth2/default',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
}
A different Custom Authorization Server can be specified:
var config = {
issuer: 'https://{yourOktaDomain}/oauth2/custom',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
}
Some applications, such as those that require access to the Okta User API, will want to use the Okta Organization Authorization Server as the issuer. In this case the issuer
should match your Okta domain:
var config = {
issuer: 'https://{yourOktaDomain}',
clientId: '{{clientId of your OIDC app}}',
redirectUri: '{{redirectUri configured in OIDC app}}',
}
Note: The Okta Organization Authorization Server is only meant for access to the Okta User API and does not support all of the features of the standard Custom Authorization Server, such as custom scopes on access tokens. It is generally recommended to use a Custom Authorization Server to secure access to your organization's resources.
clientId
Note: This configuration value can be found in the Okta Admin UI. See our developer guide for help with finding your application's clientId
Client Id of the application.
redirectUri
Note: This configuration value can be found in the Okta Admin UI under the application's "General Settings"
The URI to use for the OAuth callback.
useClassicEngine
Defaults to false
. By default, the widget will use the interaction code flow on the Identity Engine. Setting the useClassicEngine
option to true
will cause the widget to run against the Classic Engine instead. (See this document for more details on configuring a widget running in Classic Engine).
Note: This option, along with support for the Classic Engine, will be removed in a future widget version. All customers are encouraged to migrate from the Classic Engine to the Identity Engine. Visit Migrating to OIE for more details on migrating to Identity Engine.
codeChallenge
The PKCE code challenge. SPA applications will not need this option since the widget will manage the entire transaction. Web applications should generate their own code challenge and code secret. The code challenge is passed to the widget, and the code secret is held server-side to obtain tokens on the redirect login callback.
Note: Check out our sample applications for complete working examples of interaction code flow using PKCE
state
An application-provided value which will be returned as a query parameter during on the redirect login callback or email verify callback. If no value is set, then a random value will be created. When handling an email verify callback, the value of state
from the query parameter should be passed to the widget as a configuration option (along with otp). This will ensure that the widget can load and resume the current transaction.
otp
When handling an email verify callback, the value of otp
from the query parameter should be passed to the widget as a configuration option (along with state). This will ensure that the widget can load and resume the current transaction.
scopes
Defaults to ['openid', 'email']
. 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. For a list of available scopes, see Scopes and Claims.
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 formSECONDARY
- Display External IDP buttons below the Okta login form
Brand
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'
logoText
Text for alt
attribute of the logo image, logo text will only show up when logo image is not available
// Text to describe the logo
logoText: 'logo text'
brandName
The brand or company name that is displayed in messages rendered by the Sign-in Widget (for example, "Reset your {brandName
} password"). If no brandName
is provided, a generic message is rendered instead (for example, "Reset your password"). You can further customize the text that is displayed with language and text settings.
brandName: 'Spaghetti Inc.'
colors
These options let you customize the appearance of the Sign-in Widget.
If you want even more customization, you can modify the Sass source files and build the Widget.
colors.brand
Sets the brand color as the background color of the primary CTA button. Colors must be in hex format, like #008000
.
colors: {
brand: '#008000'
}
Localization
Supported languages
cs
- Czechda
- Danishde
- Germanel
- Greeken
- Englishes
- Spanishfi
- Finnishfr
- Frenchhu
- Hungarianid
- Indonesianit
- Italianja
- Japaneseko
- Koreanms
- Malaysiannb
- Norwegiannl-NL
- Dutchpl
- Polishpt-BR
- Portuguese (Brazil)ro
- Romanianru
- Russiansv
- Swedishth
- Thaitr
- Turkishuk
- Ukrainianzh-CN
- Chinese (PRC)zh-TW
- Chinese (Taiwan)
Support for additional languages can be added with the assets.languages option.
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: (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];
}
defaultCountryCode
Set the default countryCode of the widget. If no defaultCountryCode
is provided, defaults to US
. It sets the country calling code for phone number accordingly in the widget.
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
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 json files can be accessed from the
dist/labels/json
folder that is published in the npm module.
assets.languages
Specify the list of supported languages which are hosted and accessible under the path {assets.baseUrl}/labels/json/
. This option supersedes the default list of supported languages. If an unsupported language is requested (explicitly using the language option or automatically by browser detection), the default language (en
) will be used.
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: (assetPath) => {
// assetPath is relative to baseUrl
// Example assetPath to load login for 'ja': "/labels/json/login_ja.json"
return someCacheBust(assetPath);
}
}
Links
Back to sign in link
Set the following config option to override the back to sign in link URL. If not provided, the widget will navigate to Primary Auth.
backToSignInLink: 'https://www.backtosignin.com'
Note: For compatibility with previous widget versions,
signOutLink
is accepted as an alias forbackToSignInLink
Sign up link
You can add a registration link to the primary auth page by setting the following config options.
registration.click
Function that is called when the registration link is clicked.
// An example that adds a registration link underneath the login form on the primary auth page
registration: {
click: () => {
window.location.href = 'https://acme.com/sign-up';
}
}
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',
target: '_blank'
}
]
}
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, target}
that will be added after the "Help" link. The target
of the link is optional.
hCaptcha options
Set the following config options to customize hCaptcha
script URI:
// An example that uses cn1 host
hcaptcha: {
scriptSource: 'https://cn1.hcaptcha.com/1/api.js',
scriptParams: {
apihost: 'https://cn1.hcaptcha.com',
endpoint: 'https://cn1.hcaptcha.com',
assethost: 'https://assets-cn1.hcaptcha.com',
imghost: 'https://imgs-cn1.hcaptcha.com',
reportapi: 'https://reportapi-cn1.hcaptcha.com',
}
},
reCAPTCHA options
Set the following config options to customize reCAPTCHA
script URI:
// An example that uses recaptcha.net
recaptcha: {
scriptSource: 'https://recaptcha.net/recaptcha/api.js'
},
Hooks
Asynchronous callbacks can be invoked before or after a specific view is rendered. Hooks can be used to add custom logic such as instrumentation, logging, or additional user input. Normal execution is blocked while the hook function is executing and will resume after the Promise returned from the hook function resolves. Hooks can be added via config, as shown below, or at runtime using the before or after methods. The full list of views can be found in RemediationConstants.js.
// Hooks can be set in config
hooks: {
'identify': {
after: [
async function afterIdentify() {
// custom logic goes here
}
]
},
'success-redirect': {
before: [
async function beforeSuccessRedirect() {
// custom logic goes here
}
]
}
}
// Hooks can also be added at runtime
signIn.before('success-redirect', async () => {
// custom logic goes here
});
signIn.after('identify', async () => {
// custom logic goes here
});
Username and password
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: (username, operation) => {
// This example will append the '@acme.com' domain if the user has
// not entered it
return username.includes('@acme.com')
? username
: username + '@acme.com';
}
Registration
Callback functions can be provided which will be called at specific moments in the registration process.
registration: {
parseSchema: (schema, onSuccess, onFailure) => {
// handle parseSchema callback
onSuccess(schema);
},
preSubmit: (postData, onSuccess, onFailure) => {
// handle preSubmit callback
onSuccess(postData);
},
postSubmit: (response, onSuccess, onFailure) => {
// handle postsubmit callback
onSuccess(response);
}
},
parseSchema
Callback used to change the JSON schema that comes back from the Okta API.
parseSchema: (schema, onSuccess) => {
// This example will add an additional field to the registration form.
schema.push(
{
'name': 'userProfile.address',
'type': 'text',
'placeholder': 'Enter your street address',
'maxLength': 255,
'label-top': true,
'label': 'Street Address',
'required': true,
}
);
onSuccess(schema);
}
preSubmit
Callback used primarily to modify the request parameters sent to the Okta API.
preSubmit: (postData, onSuccess) => {
// This example will append the domain name to the email address if the user forgets to add it during registration.
if (!postData.userProfile.email.includes('@acme.com')) {
postData.userProfile.email += '@acme.com';
}
}
onSuccess(postData);
}
postSubmit
Callback used to primarily get control and to modify the behavior post submission to registration API.
postSubmit: (response, onSuccess) => {
// This example will log the API request body to the browser console before completing registration.
console.log(response);
onSuccess(response);
}
Handling registration callback errors
- 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: (postData, onSuccess, onFailure) => {
// A generic form level error is shown if no error object is provided
onFailure();
}
Display a form error
preSubmit: (postData, onSuccess, onFailure) => {
const error = {
"errorSummary": "Custom form level error"
};
onFailure(error);
}
Display a form field error
preSubmit: (postData, onSuccess, onFailure) => {
const error = {
"errorSummary": "API Error",
"errorCauses": [
{
"errorSummary": "Custom field level error",
"property": "userProfile.email",
}
]
};
onFailure(error);
}
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 below the login form on the Sign in form
customButtons: [{
title: 'Click Me',
className: 'btn-customAuth',
click: () => {
// clicking on the button navigates to another page
window.location.href = 'https://www.example.com';
}
}]
// An example that adds a custom button with a localized title below the Sign in form
i18n: {
en: {
'customButton.title': 'Custom Button Title',
},
},
customButtons: [{
i18nKey: 'customButton.title',
className: 'btn-customAuth',
click: () => {
// clicking on the button navigates to another page
window.location.href = 'https://www.example.com';
}
}]
customButtons.title
String that is set as the button text (set only one of title
OR i18nKey
)
customButtons.i18nKey
Custom translation key for button text specified in i18n
config option (set only one of title
OR i18nKey
)
customButtons.className
Optional class that can be added to the button
customButtons.click
Function that is called when the button is clicked
Feature flags
Enable or disable widget functionality with the following options.
features: {
showPasswordToggleOnSignInPage: true,
hideSignOutLinkInMFA: false,
rememberMe: true
}
features.showPasswordToggleOnSignInPage
Defaults to true
.
Shows eye icon to toggle visibility of the user entered password on the Okta Sign-In page. Password is hidden by default, even when this flag is enabled. Passwords are visible for 30 seconds and then hidden automatically.
features.showIdentifier
Defaults to true
.
Shows the user's identifier on any view with user context.
features.hideSignOutLinkInMFA
Defaults to false
.
Hides the "Back to sign in" link for authenticator enrollment and challenge flows.
features.rememberMe
Defaults to true
.
Pre-fills the identifier field with the previously used username.
features.autoFocus
Defaults to true
.
Automatically focuses the first input field of any form when displayed.
features.disableAutocomplete
Defaults to false
.
Sets the autocomplete attribute on input fields to off
.
cspNonce
The widget injects secure inline script/style blocks at runtime for customization purpose, but those blocks may violate CSP rules that set in the hosted web page.
cspNonce
allows set nonce value from Content-Security-Policy
header to the injected blocks, so script/style from those blocks can still be executable.
Note: nonce directive was added to CSP level2, you may still see CSP errors in browser console if it's used in unsupported browsers.
Events
Events published by the widget. Subscribe to these events using on.
ready
Triggered when the widget is ready to accept user input for the first time. Returns a context
object containing the following properties:
- controller - Current controller name
signIn.on('ready', function (context) {
// The Widget is ready for user input
});
afterError
The widget will handle most types of errors - for example, if the user enters an invalid password or there are issues authenticating. To capture an authentication state change error after it is handled and rendered by the Widget, listen to the afterError
event. You can also capture OAuth and registration errors. For other error types, it is encouraged to handle them using the renderEl
error handler.
Returns context
and error
objects containing the following properties:
context
:- controller - Current controller name
error
:- name - Name of the error triggered
- message - Error message
- statusCode - HTTP status code (if available)
- xhr - HTTP response (if available)
signIn.on('afterError', function (context, error) {
console.log(context.controller);
// reset-password
console.log(error.name);
// AuthApiError
console.log(error.message);
// The password does not meet the complexity requirements
// of the current password policy.
console.log(error.statusCode);
// 403
});
afterRender
Triggered when the widget transitions to a new page and animations have finished. Returns a context
object containing the following properties:
- controller - Current controller name
// Overriding the "Back to sign in" click action on the Forgot Password page
signIn.on('afterRender', function (context) {
if (context.controller !== 'forgot-password') {
return;
}
var backLink = document.getElementsByClassName('js-back')[0];
backLink.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
// Custom link behavior
});
});
Building the Widget
We use Yarn as our node package manager. To install Yarn, check out their install documentation.
-
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
-
Install our Node dependencies.
yarn install
-
Create a
.widgetrc.js
file in theokta-signin-widget
directory with your desired configuration:module.exports = { issuer: 'https://{yourOktaDomain}/oauth2/default', clientId: '{{clientId of your OIDC app}}', redirectUri: '{{redirectUri configured in OIDC app}}', logoText: 'Windico', features: { rememberMe: true, }, }
-
Build the widget, start a local connect server that hosts it, and launch a browser window with the widget running.
yarn start
or start local connect server in watch mode, changes in
src/
andassets/sass/
folders will trigger browser auto reload.yarn start --watch
-
Finally, enable CORS support for our new server by following these instructions. You can now authenticate to Okta using your very own, customizable widget!
Build and test commands
Command | Description |
---|---|
yarn start | Build the widget, start the server, and open a browser window with the widget loaded |
yarn start --watch | Build the widget, start the server, and open a browser window with the widget loaded and watch on widget js and sass changes |
yarn build:dev | Build an unminified version of the widget |
yarn 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 ). |
yarn test -t jest | Run unit tests using Jest |
yarn test -t jest --suiteHelp | Display optional test suite options |
yarn test -t testcafe <browser> | Run testcafe tests on selected browser (example: yarn test -t testcafe chrome ) |
yarn lint | Run eslint and scss linting tests |
Local development workflow using yarn link
When developing locally, you may want to test local changes to the widget in another project, which is also local. To use yarn link
locally, follow these steps:
In okta-signin-widget
directory:
yarn build:release
cd dist
yarn link
yarn build:webpack-dev --output-path ./dist/js --output-filename okta-sign-in.entry.js --watch
This will watch for changes in signin widget source code and automatically rebuild to the dist directory.
In your other local project directory:
yarn link @okta/okta-signin-widget
Utilizing Pseudo-loc
:warning: This tool requires access to Okta's internal registry via the VPN.
A pseudo-localized language is a test language created to identify issues with the internationalization process. Generated from login.properties
English resources, the pseudo-loc properties file can be used to test UI's for English leaks and CSS layout issues caused due to localization.
To generate pseudo-loc, run the following command:
# Navigate into the pseudo-loc package
[okta-signin-widget]$ cd packages/@okta/pseudo-loc/
# Install all required dependencies and generate login_ok_PL.properties
# NOTE: This requires VPN access
[pseudo-loc]$ yarn install
[pseudo-loc]$ yarn pseudo-loc
Finally, update the .widgetrc.js
file to use the ok_PL
language, and start the widget playground.
module.exports = {
// ...other widget config
// ...
language: 'ok-PL',
...
}
Browser support
Need to know if the Sign-In Widget supports your browser requirements? Please see Platforms, Browser, and OS Support.
Contributing
We're happy to accept contributions and PRs! Please see the contribution guide to understand how to structure a contribution.