The Assisted token JavaScript API is a library that takes care of the complete communication with Curity. It will call the OAuth server to load a new Access Token, and if the user is authenticated invisibly update the browser memory with the token. It can patch the jQuery library so that each Ajax request is prepared with the access token. Note, in order to do CORS (Cross-Origin Resource Sharing) the API server needs to either support CORS or use a proxy library of some sort.
The library is served by the Assisted Token endpoint in Curity. To enable this endpoint, configure it on the OAuth profile that is used and add it to the services that should expose it.
Once added the endpoint is configured with a base path (example: /oauth/v2/assisted-token). This path serves the Assisted Token-flow and is also the base for the library. If the endpoint is configured with the path /oauth/v2/assisted-token then the library is found under /oauth/v2/assisted-token/resources/js/assisted-token.min.js
/oauth/v2/assisted-token
/oauth/v2/assisted-token/resources/js/assisted-token.min.js
Note
The assisted-token JavaScript library is located under the sub-path resources/js/assisted-token.min.js of the assisted-token endpoint.
resources/js/assisted-token.min.js
The Assisted Token-flow is built around the ability to use iframing. Curity supports secure iframing that is configurable per client. The sites that are allowed to frame the Assisted Token-flow are configured through the client’s allowed-origins settings.
allowed-origins
If there are multiple pages that must be able to frame the Assisted Token-flow, then multiple values, or possibly a wildcard allowed-origin value can be configured. In that case, it is required to include the for_origin-parameter when making a request to the Assisted Token-endpoint on the server (i.e. the request to /oauth/v2/assisted-token).
for_origin
Please see the section on Client Framability to learn more about framability.
Any code running on the client (such as the one handling assisted token) can be inspected or even modified by other scripts running on the same page. While certain protections can be (and are) utilized to hinder this, it remains imperative that third party scripts and their providers are trusted.
fetchTokens()
login()
loginIfRequired()
isAuthenticated()
isExpired()
getAuthHeader()
prepareXHR(xhr)
prepareJQuery(jquery)
getAdditionalData()
revokeTokens()
logout()
To initialize the library a settings dictionary object is used with the following options
clientId
scope
autoPrepareJqueryAjaxForOrigins
iframeSettings
backdropSettings
closeButtonSettings
When the assisted-token.js file is loaded, the following constants are available:
assisted-token.js
curity.token.constants.authentication_endpoint
/dev/authn/authenticate?serviceProviderId=oauth-test
curity.token.constants.hostUrl
https://localhost:8443
curity.token.constants.logout_endpoint
/dev/authn/authenticate/logout?serviceProviderId=oauth-test
curity.token.constants.revoke_endpoint
/assisted-token/revoke
curity.token.constants.token_endpoint
/assisted-token
The library relies on the DOM to be loaded, so the script that initializes the library should be inside the <body>, or be run after the DOM is ready, i.e. inside jQuery.ready().
The following section illustrates some example usages of the library.
There are live examples that can be experimented with in the <installation>/examples/clients/assisted-token-website
<installation>/examples/clients/assisted-token-website
This example does not let the user see anything, but assumes that the SSO session exists already that will auto-login the user when the authorize endpoint is reached. Commonly this happens with the user needed to authenticate in the first placed to reach the website at all.
<body> ... <script> var settings = { clientId: "client-assisted-example", autoPrepareJqueryAjaxForOrigins: ['^/.*$'], //Inject tokens into jQuery ajax requests relative to where this file is hosted } var assistant = curity.token.assistant(settings); assistant.fetchTokens().then(function(){ console.log("We are now logged in..."); //Now get some data $.get(...); }).fail(function(err){ console.log("Failed to login", err); });
<body> ... <script> var settings = { clientId: "client-assisted-example", autoPrepareJqueryAjaxForOrigins: ['^/.*$'], iframeSettings: { 'width' : '320', 'height' : '600', 'style' : "z-index:100;position:absolute;top:20px;left:50%;margin-left:-160px;border:0;overflow:hidden;box-shadow: 0px 0px 10px #888888;" }, backdropSettings: { 'visible' : 'static', 'class' : 'customBackdropClass', 'style' : "width:100%;height:100%;position:fixed;top:0;left:0;z-index:50;background:#8282ce;opacity: 0.4;filter: alpha(opacity=40);" } }; var assistant = curity.token.assistant(settings); assistant.loginIfRequired().then(function(){ console.log("We are now logged in..."); //Now get some data $.get(...); }).fail(function(err){ console.log("Failed to login", err); });
Some times it’s useful to know if the library has valid tokens, and if not, fetch new ones.
... var assistant = curity.token.assistant(settings) ... if(!assistant.isAuthenticated() || !assistant.isExpired()){ assistant.fetchTokens().then(...).fail(...); }
If a client configures multiple values for allowed-origins, the URL of the framing page must be provided. This can be done by including it in the settings:
<body> ... <script> var settings = { clientId: "client-assisted-example", autoPrepareJqueryAjaxForOrigins: ['^/.*$'], iframeSettings: { 'width' : '320', 'height' : '600', 'style' : "z-index:100;position:absolute;top:20px;left:50%;margin-left:-160px;border:0;overflow:hidden;box-shadow: 0px 0px 10px #888888;" }, for_origin: "https://main-page.example.com" } ...
This enables that the Assisted Token-flow can be executed from https://main-page.example.com. Note that it does require the client to have the value https://main-page.example.com configured for allowed-origins. Also note, that when the only configured value is https://main-page.example.com, it does not need to be explicitly provided.
https://main-page.example.com
This example enforces authentication even if there is an existing, valid SSO session.
<body> ... <script> var settings = { clientId: "client-assisted-example", autoPrepareJqueryAjax: true, //default false } var assistant = curity.token.assistant(settings); assistant.login({ force_auth: true //Enforcing authentication; ignoring any existing SSO session }).then(function(){ console.log("We are now logged in..."); //Now get some data $.get(...); }).fail(function(err){ console.log("Failed to login", err); }); ...
When tokens are automatically injected into jQuery Ajax requests it’s important to make sure those tokens aren’t sent to unintended remote origins. Even when such origins are trusted by the client, they might not be a trusted recipient of the token in question.
<body> ... <script> var settings = { clientId: "client-assisted-example", autoPrepareJqueryAjaxForOrigins: [ '^/.*$', // (1) Inject token in all requests relative to the origin of this file '^https://example.com/api/*', // (2) Inject token in all requests under 'https://example.com/api/' '^https://example.com/api2/info$', // (3) Inject token in all requests to exactly 'https://example.com/api2/info' ] }; var assistant = curity.token.assistant(settings); ... $.get('/api').done(...); // Token injected; request matched in white-Listing #1 $.get('https://example.com/api/').done(...); // Token injected; request matched in white-Listing #2 $.get('https://example.com/api/resource').done(...); // Token injected; request matched in white-Listing #2 $.get('https://example.com/api2/info').done(...); // Token injected; request matched in white-Listing #3 $.get('https://example.com/api2/resource').done(...); // Token not injected; request not matched in white-list $.get('https://evil.example.com/api/').done(...); // Token not injected; request not matched in white-list ... assistant.prepareJQuery($, true); // Bypass white-listing $.get('https://evil.example.com/api/').done(...); // Token injected; white-list bypassed
This example shows how to revoke the current tokens and logout the active SSO session.
<body> ... <script> var settings = { clientId: "client-assisted-example" } var assistant = curity.token.assistant(settings); assistant.logout().then(function(){ console.log("We are now logged out"); }).fail(function(err){ console.log("Failed to logout", err); }); ...
The Assisted Token flow relies on integrating Curity’s authentication and token services into a JavaScript controlled application, both of which most likely run on their own DNS-domain. Having this separation may cause issues with modern browsers, that distinguish between requests to first parties and to third parties. An approach to overcome this being a problem, is described in the section Third Party Cookies.
When running both the example Assisted Token website as well as Curity from localhost, they will both be considered first party websites (they’re sourced from the same domain), so third party cookies are not an issue in that case. However when the example Assisted Token website is put on another domain, there are two things to do to enable preflighting to make Curity a first party:
localhost
1. Add the domain to the redirect url whitelist of the authentication service that is linked to the token service to which the Assisted Token endpoint belongs to Uncomment the <script ...preflight.min.js"> tags in the assisted-token-website’s index.html.
1. Add the domain to the redirect url whitelist of the authentication service that is linked to the token service to which the Assisted Token endpoint belongs to
<script ...preflight.min.js">
index.html
For information about how to obtain this preflight script URI, refer to Steps to Integrate Preflighting.
settings
The settings object is used to initialize the library.
RegExp()
width
height
scrolling
style
iframes
targetElementId
visible
backdropClass
button
wrapperStyle
wrapperClass
div
authAndTokenParameters
A set of optional parameters that can be passed to token retrieval functions.
force_auth
freshness
acr
reuse
curity.token.
assistant
Creates a new assisted token assistant object that gets initialized with the server details
A helper object that contains the initialized library.
assistant.
login
Opens a visible iframe and starts the authentication flow. This is used when the user is not assumed to be authenticated.
A promise that will be resolved with a dictionary object with token and expiration.
token
expiration
fetchTokens
Opens a hidden iframe and calls the OAuth servers assisted-token endpoint. It assumes an SSO session to be available
A promise that will be resolved with a dictionary object with token and expiration, or an error object if rejected with a dictionary with an error_description field.
error_description
loginIfRequired
First attempts to retrieve a token using a hidden frame, if this cannot be done, it retries using a visible frame to allow the user to enter its credentials and authenticate.
isAuthenticated
isExpired
getAuthHeader
prepareXHR
Patches the XMLHttpRequest object by adding the token to the Authorization header for the request.
prepareJQuery
Patches jQuery by adding a beforeSend hook that makes sure that the Access token is available in the Authorization header.
curity.token.assistant()
getAdditionalData
revokeTokens
Revokes the current tokens.
logout
Revokes the current tokens, and terminates the active SSO Session.