Authentication

Finsemble provides a UI for authenticating end users, a "boot stage" for performing authentication related tasks (such as fetching entitlements or dynamically generating config), and APIs for sharing user credentials among cross-origin components.

Authentication involves the following:

  1. Finsemble's Authentication Client API
  2. Finsemble's "Authentication Service"
  3. Authentication Components (that you build)

Finsemble is capable of supporting any authentication protocol. This tutorial provides information to implement nearly any authentication scenario but focuses on the three most common approaches:

  1. Prompting the user for login/password (session based authentication)

  2. Automatic login with Windows credentials (aka "negotiate protocol")

  3. Oauth/OpenID ("identify provider")

    Skip to the section that matches your firm's authentication practices.

Finsemble's boot sequence runs an "authentication stage" before any components or workspaces are loaded. During this stage you can run authentication or initialization related code. You can run code that presents your users with a password prompt, or code that performs tasks invisibly.

Enabling authentication

To enable authentication at startup you must configure the "startup" authentication profile by making config entries. authentication is located at the top level of Finsemble's config (configs/application/config.json). Adding a "startup" entry will cause Finsemble to run the authentication stage.

Example: Configure Finsemble to prompt users for a username and password

    "authentication": {
        "startup": {
             "component": "Authentication",
             "adapter": "PASSWORD",
         }
     }

startup - A special "authentication profile" that runs during Finsemble's boot sequence. (Creating additional authentication profiles is an advanced topic covered later in this tutorial.).

component - The name of the Finsemble Component that collects login and password (in configs/application/components.json). Your component can be fully customized. The only requirement is that it calls FSBL.Clients.AuthenticationClient.publishAuthorization when it is complete (to allow Finsemble to finish its boot sequence).

adapter - Finsemble's "authentication service" uses this to decide which authentication protocol to use. "PASSWORD" and "OAUTH" are supported.

Building Authentication Components

In Finsemble Seed, src/components/authentication contains a sample authentication component built with React. It is described by the config entry components.Authentication (in components.json). You can use this sample component as a starting point or write your own.

When using the "PASSWORD" adapter, Finsemble expects your component to fully handle the process of authenticating your users. Your Authentication Component should collect and send the user's credentials (login, password, etc) to your back end server for authentication. The connection to your back end can use any web technology (e.g. AJAX, Websocket, etc).

Once your component has successfully completed authentication, it must tell Finsemble call FSBL.Clients.AuthenticationClient.publishAuthorization(user, credentials) so that Finsemble's boot sequence can resume:

  • user - A string that identifies the user. This is used as a "key" by Finsemble's Storage Service to prevent storage conflicts with saved data from other users. (This is particularly important if you support multiple user logins to the same computer and use localStorage for data.)

  • credentials - An object that may contain any useful values. The "credentials" object is publicly available to all Finsemble components. Credentials are often used by components to perform Single Sign On (SSO) operations - because they can trust the source of the credentials (Finsemble). (See below for information on subscribing and retrieving credentials).

Note: Never rely on HTML components to store sensitive data. Browser data can be easily accessed by technical users. A user can easily use Chrome tools to manually run publishAuthorization() or to get access to the credentials object. You must program your desktop software just as you would program web software, using secure schemes such as session tokens to protect access. Your application components must operate according to these principles unless your desktop and browser are configured to use NTLM, Negotiate, Kerberos or another secure protocol.

Note: In cases where your authentication model requires handing control off to an authentication server (such as OAuth 2.0), then the "redirect page" from the authentication server should call publishAuthorization().

Note: Clicking on the "close icon" in the Authentication Component will cause Finsemble to shutdown. This prevents users from ever getting into a state where they cannot terminate your SmartDesktop.

Building An Authentication Component Using React

Finsemble's example authentication component is built using the Finsemble React UI. The only important difference is that instead of calling publishAuthorization() imperatively, this component uses the authorize() method provided by Finsemble's useAuth() React hook.

Invisible Authentication

Your desktop may be able to authenticate users automatically (such as with "NTLM" or "negotiate" protocols) but you may still need to run code during Finsemble's authentication boot stage. Common use cases include fetching user entitlements or setting "dynamic config" (see below).

Finsemble's authentication component can be run "invisibly" by adding this setting to its config: window.options.autoshow = false.

Note: If your authentication process takes more than a few seconds you may want to avoid using invisible authentication. Instead, create a visible authentication component that simply provides a progress bar or some sort of visual indicator. This is a particularly good idea if it is possible for your authentication process to "block". The "close icon" in the authentication component provides users with a way of terminating your SmartDesktop if it fails to start.

Dynamic Config

"Dynamic Configuration" is our term for updating Finsemble's config at runtime by making calls to FSBL.Clients.ConfigClient.processAndSet().

The most common use of "dynamic config" is to configure the user's desktop environment once the user has been identified. Typical environmental configs that are set dynamically include:

  • components - The list of components available for launching can be dynamically generated based on the user's identity and their entitlements. Often, the list is generated by a back end server that can output Finsemble compatible config.

  • workspaces - A firm may decide to provide example workspaces to its users. The authentication boot stage is a great point to load those workspaces, particularly if the list of workspaces is keyed to user type.

The Finsemble's authentication boot stage provides a natural point to generate and set dynamic config. Typically, this is done by making calls to processAndSet() directly in your authentication component.

Subscribing To and Retrieving Credentials

Any Finsemble component or service can subscribe to or retrieve authorization credentials.

Example: subscribe to authorization credentials:

FSBL.RouterClient.subscribe("Authorization", function (err, response) {
	if (err) return /* handle error*/;
	let credentials = response.data;
	// ...
});

Example: retrieve authorization credentials:

FSBL.AuthenticationClient.getCurrentCredentials(function (err, credentials) {
	if (err) return /* handle error*/;
	// ...
});

Session Tokens and Cookies

Typical web session-based authentication uses a browser cookie to store a session token. The token is passed with each request back to the webserver as a cookie. The webserver checks the token against its internal map of authenticated sessions before returning data.

Browser cookies are "origin based". If the session cookie is set within your authentication component then the cookie will automatically available to any other component or service that is hosted on the same origin (domain). If you're building code within the Finsemble Seed project structure then this will mean that all of your components and services will share cookies (unless your server sets cookie path in your http headers).

In other words, cookies in Finsemble behave exactly as they behave in a web browser. (Please note that origins must match exactly! http://google.com and https://google.com are different origins)

If you need to share cookies among components that are hosted on different origins then you can shared them inside Finsemble's authentication credentials or with the distributed store.


The Authentication Sequence: Step By Step

When a SmartDesktop launches, the following authentication sequence occurs:

  1. At Finsemble's "authentication" boot stage, config is checked for the existence of "authentication.startup". If it exists, then steps 2, 3 & 4 are executed.

  2. Finsemble's Authentication Service spawns the configured authentication component and waits for publishAuthorization() to be called.

  3. Your code runs in the authentication component. This code should authenticate the user and then call publishAuthorization(username, credentials).

  4. Finsemble's Authentication Service publishes the username and credentials to all listeners on a PubSub topic "Authorization" and makes it available to getCurrentCredentials().


Automatic Authentication With Windows Login Credentials

If your organization has an authenticated network environment, you can use Integrated Windows Authentication (IWA) to automatically authenticate Finsemble using the user’s Windows login credentials.

When using Windows credentials on a trusted network, Finsemble itself does not actually play a role in authentication. Rather, your servers interact directly with Chromium via the negotiate protocol (Finsemble components are displayed by the Chromium engine).

The request will be invisibly validated by Chromium via either Microsoft Kerberos or NTLM.

Configuring Finsemble For Windows Authentication

When your network is configured for automatic authentication through Windows you should disable authentication in Finsemble. Remove the authentication.startup entry in your config (configs/application/config.json). Your SmartDesktop will now boot without prompting the user to log in.

However, there are still some considerations even when authentication is automatic.

  • You may still need to perform authentication related tasks during boot. In this case, you should use the "invisible authentication" techniques described above, completing authentication related tasks in an invisible Authentication Component that you create.

  • You may still need to fetch credentials. When using automatic authentication on Windows, your user’s credentials are not accessible in the browser. To fetch credentials requires implementing your own custom API into your web server's infrastructure. This can also be done inside an "invisible" Authentication Component as described above.

Please remember, when using invisible authentication components you must still call publishAuthorization() for the boot sequence to proceed.

How Windows Authentication Works : Step By Step

  1. A Finsemble component or service requests content from your server (e.g., an HTML file, WebSocket connection, or API call).

  2. Your server responds with a request to authenticate with the Negotiate protocol specified. This is very similar to how HTTP basic or digest authorization work, but Negotiate does not result in a pop up to the user. Instead, if the server is on a trusted network, Chromium automatically makes a request for the user's credentials via Kerberos or NTLM protocols.

    A trusted server is (a) on the same LAN (same IP network/submask), or (b) configured as a trusted server within Windows (this works the same way as Internet Explorer does). Your network administrator will likely configure your end users' machines to trust your server through group policy management.

  3. Chromium automatically responds back to the server with the Windows credentials.

  4. The server validates the credentials by making its own connection to the Windows LAN/Kerberos server. If validated, the content will be delivered; otherwise a 503 Unauthorized message will appear in the component window.

  5. Subsequent components connecting to this server will receive their content immediately because Chromium will return valid credentials for any window that connects to the same, already-authorized, domain.


Oauth Authenticaion

OAuth 2.0/OpenID

With OAuth, applications (such as your Finsemble SmartDesktop) can defer authentication to an external "identity provider." On the web, firms like Google and Facebook play the role of identity provider. Your firm may have its own identity service that supports OAuth. OAuth is made possible through a "shared secret" between the identity provider and the application. Behind the scenes, it is affected through a series of redirects.

Note: Finsemble’s implementation uses OAuth2 server flow (not implicit flow).

Set an authentication config. We call this an authentication profile:

"startup": {
	"adapter": "OAUTH2",

// The url of your identity provider’s login page. You can add additional query string parameters to this if necessary.
// For instance, MS ADFS sometimes requires a non-standard "resource" parameter.
// Another example would be https://accounts.google.com/o/oauth2/v2/auth?prompt=consent which controls how Google presents its OAuth page.
"authorization_endpoint": "https://openid.c2id.com/login",

// The type of OAuth request
"scope": "openid",

// This will be provided by your identity provider
"client_id": "XYZABC",

// Your OAuth server side script
"backchannel_endpoint": "https://yoursite/authenticate",

// Your redirect_uri should point to an `oauthResponse.html` page.
// Follow this tutorial to create an `oauthResponse.html` page (see below). The file name isn't dictated, but it must match the entry in *authentication*.
"redirect_uri": "$applicationRoot/src/components/authentication/oauthResponse.html",

// Optionally specify which component to use to spawn this profile
"component": "Authentication"
}

If you’re familiar with OAuth, Finsemble is automatically generating the following fields: state, response_type, and redirect_uri.

startup is a special authentication profile which causes Finsemble to wait for authentication before proceeding. You can create additional profiles, and call them using AuthenticationClient.beginAuthentication(), such as when you have a third-party component which requires OAuth.

Stage 1: With this configuration in place, Finsemble display the page at authorization_endpoint as a modal when it’s launched. The end user will log in to this modal. Upon successful login, the identity provider will redirect to Finsemble’s built in OAuth component. This component will validate and process the response for the next stage.

Stage 2: Finsemble’s OAuth component will then make a post request to the URL you specified in backchannel_endpoint. This request will contain client_id, grant_type, code and redirect_url. backchannel_endpoint should point to a server page that you host which should add the client_secret, and then forward this information via a /token request to your identity provider’s token_endpoint. The results should be returned back to the Finsemble request.

Finsemble will receive the results. It will process and publish the results as "credentials" via FSBL.Clients.AuthenticationClient.publishAuthorization. If the results include an id_token then it will be decoded and parsed. The parsed variables will be made available in the credentials object. If those results include a "sub" field, then that will be set as the Finsemble user. Otherwise, the access_token will be set as the Finsemble user.

The application will start and your components can use the contents of the credentials object where needed.

Note: The client_id and client_secret should be encoded based on the specifications of your identity provider. Some require that these be base64 encoded into an HTTP header. Some can accept them as post parameters.

Currently, credentials are available to all components.

During development, you can skip the server stage by including client_secret in your authentication config. This can make development easier but should not be done in production.

OAuth response example

The redirect_uri registered in the authentication config must point to an oauthResponse.html page. The oauthResponse.html response page can have HTML, CSS, and JavaScript for a consistent, branded experience for your company. It will be useful to create handlers for window close and errors.

If the user attempts to close the window without completing the OAuth sign-in process, 1) they will not be authorized in Finsemble and 2) the application will take the action that you specify. In this example, when the end user closes the authentication window and the user isn't logged in, we assume that the user failed to sign in via OAuth; therefore we shut down the entire app. Otherwise, if we were just using the window to authenticate a client, we close the window but keep Finsemble running.

Example:

closeThisWindow() {
 FSBL.Clients.AuthenticationClient.getCurrentCredentials((err, credentials) => {
   if (!credentials) {
     FSBL.shutdownApplication();
   } else {
     FSBL.Clients.WindowClient.getCurrentWindow().close();
   }
 });
}

Your desired user experience may vary. For example, instead of executing FSBL.shutdownApplication();, you may choose to prompt the end user to attempt the authentication process again.

Necessary Finsemble handler

There is one specific FSBL method that must be used to publish the user's authorization for the application: FSBL.Clients.AuthenticationClient.completeOAUTH(). Here is an example:

FSBL.Clients.AuthenticationClient.completeOAUTH(null, null, (err, response) => {
	if (err) {
		showError(err);
	} else {
		const credentials = response;
		runBusinessLogic(credentials, () => {
			// In the special case of "startup", we publish the authorization, which releases Finsemble and lets it start.
			if (credentials.config.name === "startup") {
				// "sub" is the user ID provided by the OpenID provider. Not all OpenID providers support this. If not supported, then just set the user to the access token returned by the OAuth service.
				const user = credentials.sub;
				if (!user) {
					user = credentials.access_token;
				}
				// Finish the authentication process
				FSBL.Clients.RouterClient.transmit(
					"AuthenticationService.authorization",
					{ user: user, credentials: credentials }
				);
			}
			closeThisWindow();
		});
	}
});

Note that showError, runBusinessLogic, and closeThisWindow are not FSBL methods—they are functions you may write to streamline the handler code. For example, you may need runBusinessLogic to do more work than only publish the end user's authorization by coupling the workflow to additional services.

Backchannel endpoint

The remaining piece in the workflow is the backchannel endpoint registered in the authentication config. This will point to your backend service that will use your OAuth secret token to fulfill the OAuth request to the identity provider. The logic needed by this endpoint is dependent upon your provider.

Note: Remember, your OAuth secret token must remain secured in a server-side application and never exposed in JavaScript.

Using OAuth to retrieve an access_token for API usage

OAuth can be used to access third-party resources. In this scenario, the end user is presented with login credentials from the third party. Once authenticated through a series of redirects, the client application is provided with an access_token which it can use to access the third-party resources.

Create an OAuth2 profile as described above but with a specific name. You can then use AuthenticationClient#beginAuthentication to kick off the process of retrieving an access_token. When that process is complete, the callback will be returned with the access_token and other credentials. See AuthenticationClient#completeOAUTH for implementation details.


check   Finsemble is agnostic about which type of authentication you may choose to implement, but comes with hooks for you to add whatever authentication component best fits your organization's needs.
 

Further reading

The Authentication Client documentation provides additional context.

Authentication is empowered by dynamic configuration which provides end users the applications and workspace layouts to which they are entitled.

For more information on how Finsemble handles start-up, check out Finsemble's Lifecycle Events.

The following sources are useful as references for the authentication process:

This document describes the browser authentication protocols in more detail: