Authentication
We will discuss here the general rules followed by ActiveUI regarding authorization and authentication against the servers it communicates with.
General Principles
No Security client side
Since ActiveUI runs inside a Web browser its code is considered always inspectable and alterable. Thus, it does not contain any security enforcement mechanisms and nothing sensitive such as passwords will be stored by ActiveUI SDK in the browser. All the authorization checks are done server side. ActiveUI's goal is to provide UI and logic to ask the credentials to the user and use them to authenticate against the servers, nothing more.
Security only when Needed
ActiveUI can also be used to process and display static or public data. In these situations, the user doesn't need to authenticate against ActivePivot. This is why the authentication user interface is displayed at the last moment: when a server responds to an HTTP request with a 401 status code.
JWT
The underlying technology used to safely store credentials in ActiveUI and transfer them to the servers is JWT. It is recommended to get familiar with it: Wikipedia article and JWT website.
Roles
The JWT contains the ordered list of roles the user has. This is used by ActiveUI in some components to decide which roles to assign to created objects. For instance, bookmarks and KPIs will by default use the roles of the user in their permissions. This is just for convenience, since the server (Content Server or ActiveMonitor) will check on its side that the roles of the created content are allowed by the JWT.
Default Behavior
By default, ActiveUI will use JSON Web Tokens for its authentication with ActivePivot, ActiveMonitor and the Content Server.
When trying to communicate with any of these servers, if ActiveUI receives a 401 HTTP response, it will use the first Content Server it knows of to generate a JWT.
This token will be stored in the local storage of the browser and sent along every request in the Authorization
header.
Reuse ActiveUI Authentication
The API of ActiveUI can be used in order to call project-specific server-side endpoints that would share the same security as the ActivePivot server. In order to do so, the following code can be used as an inspiration:
// Fetching the discovery and logging it
const requestOptions = await activeUI.security.getRequestOptions();
const response = await fetch(
'https://activepivot:port/pivot/rest/v3/cube/discovery',
requestOptions,
);
const result = await response.json();
console.log(result);
For more documentation on:
fetch
, read its documentation on MDN.- the
requestOptions
returned bygetRequestOptions
, seeAuthenticationHolderImplementationProperties
.
The content of requestOptions
depends on the authentication-holder
plugin implementation being used.
Sequence Diagrams
The interaction between the different actors of the authentication will be represented with sequence diagrams. In these sequence diagrams the Browser runs ActiveUI code so it includes it as well as the cookies and redirect logic.
First Authentication
The sequence diagram of the first authentication on the first launch is:
The WebSocket part of the authentication will be described below.
Token Refresh
The JWT produced by the Content Server will expire at some point (this is configured in the Content Server), triggering the token refresh process:
The rest of the process is the same than on first connect.
Token Sharing
ActiveUI will use a single JWT to communicate with all the servers. This is how a user can enter their credentials only once and be able to connect to multiple ActivePivot servers. The constraint on the servers is that all security filters should validate with the public key corresponding to the private key the Content Server used when generating the token.
Token Storage
ActiveUI will store the token in the local storage, so that when a user closes then reopen the browser the user doesn't need to enter their credentials again. It will store along it the username entered by the user so that when the token expires we can already fill the username in the "Log in" popup. A malicious browser extension or other person with access to the browser could steal this token, but could then gain server access only for the TTL of this token.
This TTL duration is controlled by the Content Server, and is recommended to be approximatelly a day or half a day of work. A longer duration is not recommended because of the possibility of token theft. A shorter duration is also not recommended because token expiration requires the user to enter their credentials again which would be not user friendly when happening many times a day.
Password Storage
The password entered by the user is handled briefly by ActiveUI to create the Authentication
header (using Basic Access Authentication) to retrieve the JWT.
After that, the password is not kept anywhere so no extensions or other user could steal it.
Cloud Security (Keycloak)
The cloud security relies on Keycloak. Among all features that Keycload includes, the ones important for ActiveUI is that it follows the OAuth2 protocol and uses JWT. ActiveUI interaction with server security is quite different in this situation. ActiveUI is served by a server with a Keycloak compatible security filter. This means that the user must log in before using ActiveUI. ActiveUI will then work with Keycloak JWT.
First Authentication
The steps in italic are implemented in ActiveViam products, either ActiveUI or ActiveViam web components used in ActiveCloud. The other steps are part of Keycloak server and the security filters it provides.
The above process has quite interesting properties:
- Almost all the steps are pure Keycloak implementation, this process follows the OAuth2 protocol.
- There are a lot more steps than in the pure JWT implementation, this is because this protocol has more capabilities than a pure JWT-based implementation like the default behavior.
- No ActiveViam components (neither ActiveUI nor ActivePivot nor the Content Server) see the user credentials at some point, they all work only with the JWT produced by Keycloak.
- There is not only one token. We saw a Single Usage Token, an Access Token, and there is also a Refresh Token that will be described below.
- The Access Token stored by ActiveUI at the end of the process is sufficient to connect to every ActiveViam server with the right roles. This means that all servers that this ActiveUI will connect to should validate in their security filters the Access Token produced by Keycloak. They should thus have the public key corresponding to Keycloak private key in their security configuration.
Next Authentication Shortly After
The next time the user opens the ActiveUI application while the S2 cookie is still alive (basically after having closed then reopening the browser, see Timeouts), the following process starts:
The session mechanism of the Content Server is sufficient here, there is no need to communicate with the Keycloak server.
Next Authentication
If the user reopens ActiveUI later (basically the next day, see Timeouts), we will use the Refresh Token mechanism of OAuth2. The Refresh Token is also a token generated by Keycloak and stored on the Content Server (it is quite sensitive so it should never go client side). The goal of this token is to recreate an Access Token from it from time to time. On almost every request to a server, the server will quickly check the validity of the Access Token. Once in a while, when the Access Token expires, ActiveUI and the Content Server will reach up to the Keycloak server to check if the user has not been removed in the meantime. The Access Token acts like an authentication cache that can be checked very quickly, the Refresh Token is more expensive to check but more powerful.
Request on Server with expired Access Token
We describe now what happens when ActiveUI performs an HTTP request on a server like ActivePivot or ActiveMonitor and its Access Token has expired:
We see here that in this situation, Keycloak is asked to produce a new token and can deny the request if the corresponding account was terminated in the meantime. In the above situation, everything goes well. On the other hand if the user has been kicked out we will have the following sequence:
When the Keycloak server tells ActiveUI (via the Content Server) that the user is no longer connected, ActiveUI will open a pop-up containing the Keycloak login form. Once the user has validated the form ActiveUI will be able to ask again the Content Server its Access Token and resume its operations. During all these steps all HTTP queries are paused and will resume transparently with the new credentials.
Keycloak Timeouts
A Keycloak authentication flows uses the following authorization holders that have each a different timeout:
Bearer | Role | Recommended TTL |
---|---|---|
Access Token | Connect to ActivePivot, Sentinel and Content Servers | 15 minutes |
Refresh Token | Recreate Access Token when it expired | 30 days |
Content Server Cookie | Find Acces Token | 15 minutes |
Keycloak Cookie | Reconnect to Keycloak when Access Token expired to find again Refresh Token | 30 days |
ActivePivot Server Cookie | Bridge between REST and WebSocket security | 1 minute |
These recommended TTL are the consequence of the following observations:
- The Access Token can have a short TTL since its refresh does not require any user interaction.
- The Access Token TTL should not be very short since it still requires multiple HTTP calls and Database reads when it expires.
- The Access Token should not have a too long TTL otherwise users could continue to use the system for a long time even though the administrator banned them.
- It would be too expensive to ask Keycloak on each call if the Access Token represents a user that was not banned, so the Access Token cannot be revoked.
- The Refresh Token can be revoked since we ask Keycloak everytime we use it.
- The Refresh Token never leaves the Servers so it cannot be stolen and can thus have a longer TTL.
- Cookies should have a similar TTL than the token they carry otherwise they would maintain sessions with expired tokens.
- Keycloak invalidates the sessions when a logout happens so it is safe to give a long TTL to Keycloak cookies.
- The ActivePivot Server Cookie usage is always very short so we don't need to give it a long duration.
Token Storage
When Keycloak is used, ActiveUI doesn't even persist the Access Token it uses (since the cookie is sufficient). The Content Server stores the Access and Refresh Tokens in its sessions.
Password storage
When used with Keycloak, ActiveUI never sees any credentials. All the login forms are served by the Keycloak servers via redirects so no ActiveViam components have access to the credentials.
Implementation and Configuration Details
The type of security can be configured through the ActiveUIOptions
, by setting the securityType
property to the plugin key of the desired authentication-holder
plugin implementation.
WebSockets
The above documentation was relevant for REST calls, but WeSocket authentication is quite different.
This is due to the fact that the WebSocket Client API does not allow ActiveUI to send an Authorization
header when opening a WebSocket, which limits greatly our authentication mechanisms.
We can only rely on the cookies to authenticate WebSockets. So we solve this by first performing an HTTP request with a JWT. This request will create a session on the target server that we will then be able to use for our WebSocket. This gives the following sequence: