This the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Documentation

Version 1.0

This first version of Butler Auth includes support for these authentication providers:

  • Google
  • Microsoft
  • Okta
  • Auth0
  • Keycloak
  • Facebook
  • LDAP
  • Local file
  • Single user

Docker containers are available on Docker Hub for both Intel and ARM architectures.

1 - About

Information about the Butler Auth software, community, docs and more.

1.1 - Butler Auth

An introduction to Butler Auth.

The goal of the Butler Auth project is to make it easy to add strong/flexible/custom authentication strategies to Qlik Sense Enterprise on Windows (QSEoW).

QSEoW has very good, built-in access control and authorization.
In practice this means that QSEoW enforces that users only can access resources they are allowed to access.

There is however no authentication what so ever in QSEoW.
This is quite reasonable - Qlik Sense is an analytics tool and should focus on this rather than the intricancies of ensuring that users are who they claim to be. That job is better left to those specializing in that particular field.

Butler Auth is the link between QSEoW and services that specialize in authentication and security.

Technology stack

Butler Auth is written in Node.js and runs on most modern operating systems.
Some authentication providers are developed as part of the Butler Auth project, but most come from Passport.js.

You can run Butler Auth on the same server as Qlik Sense, in a Docker container on a Linux server, in Kubernetes, on Mac OS, on Raspberry Pi (not a good idea.. but possible and proven to work).

Butler Auth is a member of a group of tools collectively referred to as the “Butler family”, more info here.

This picture might be useful to understand what Butle Auth does and how it fits into the larger system map around Qlik Sense:

Butler Auth system overview

1.2 - The Butler family

Please meet the Butlers. They’re a nice, wild bunch!

Butler Auth is part of a group of tools that all aim to improve, simplify or extend various aspects of Qlik products.
Most tools focus on Qlik Sense Enterprise on Windows, but some have wider use within the Qlik ecosystem.

All members of the Butler family can be downloaded from Ptarmigan Labs' GitHub page.
Development of the Butler tools is sponsored by Ptarmigan Labs AB, which is an IT consultancy company in Stockholm, Sweden.

Projects with production grade release status are (as of this writing):

Butler Auth

Makes it easier to add strong/flexible/custom authentication flows to Qlik Sense Enterprise on Windows.
Out of the box Butler Auth supports Google, Microsoft, Facebook, Okta, Auth0, LDAP and a few more authentication providers.

Butler Auth is designed to be extensible. It’s therefore relatively easy to add new authentication providers.

butler-auth.ptarmiganlabs.com (This site!)

Butler

The original Butler. Offers various utilities that make it easier to develop Sense apps, as well as simplifying day 2 operations.

butler.ptarmiganlabs.com

Butler SOS

Real-time operational metrics for Qlik Sense.
It simplifies day 2 operations ([1], [2]) and is a must-have if you are responsible for a Sense environment with more than a dozen or so users.

Key features include

  • Storing operational metrics to InfluxDB, for later viewing in Grafana dashboards.
  • Extract warnings and errors from Sense. Makes it much easier to detect (and act!) on issues as they happen, rather than in retrospect much later.

butler-sos.ptarmiganlabs.com

Butler CW

Butler Cache Warmer. Cache warming is the process of proactively forcing Sense apps to be loaded into the Sense server’s memory, so they are readily available when users open them.

Once again - if your Sense environment serve more than a dozen users, you should consider a cache warming tool.

github.com/ptarmiganlabs/butler-cw

Butler App Duplicator

No matter if you are a single developer creating Sense apps, or have lots of developers doing this, having app templates is a good idea:

  • Lowered barrier of entry for new Sense developers.
  • Productivity boost when developing Sense apps.
  • Encouraging a common coding style and standard across all apps.

github.com/ptarmiganlabs/butler-app-duplicator

Butler Spyglass

This tool is mainly of interest if you have lots of QVDs and apps, but when that’s the case it’s of paramount importance to understand what apps use which QVDs. In other words what data lineage looks like.

Butler Spyglass also extracts full load scripts for all Sense apps, creating a historical record of all load scripts for all Sense apps.

github.com/ptarmiganlabs/butler-spyglass

Butler Notifier

This tool makes it easy to tap into the Qlik Sense notification API. From there you can get all kinds of notifications, including task reload failures and changes in session state (user login/logout etc).

github.com/ptarmiganlabs/butler-notifier

Butler Icon Uploader

Visual looks is important when it comes to analytics, and this holds true also for Sense apps. The Butler Icon Uploader makes it easy to upload icon libraries (for example Font Awesome) to Qlik Sense Enterprise.
With such icons available, Sense app developers can then use professional quality sheet and app icons in their Sense apps.

github.com/ptarmiganlabs/butler-icon-upload

1.3 - Use cases

How can Butler Auth be used?

Log into QSEoW using one of the major cloud providers' directory service

If you already use Microsoft Azure, Google, Okta or Auth0 as identify provider, you probably want to do the same also for Qlik Sense.

Log into QSEoW using LDAP for as both user and credentials

A very common setup (possibly the most common) is to use Active Directory for storing user info and credentials, and then talk to AD using the LDAP protocol.

QSEoW natively supports syncing user names from some service using LDAP, this does not include passwords though.
This is actually not authentication at all, it’s just a way to sync user names and attributes from a directory service to QSEoW, using the LDAP protocol.

LDAP can however also be used to authenticate users, and Butler Auth supports this.

One use case is thus to get both the Qlik Sense user directory info (i.e. user names and attributes) and authenticate users via LDAP.

Authenticate against Keycloak for a fully open source setup

Keycloak is a very powerful, open source identity provider.

In situations where open source solutions are preferred or mandated the combination of Keycloak and Butler Auth provides a 100% open source authentication solution for QSEoW.

Increaseed redundancy by offering sign-in via multiple channels

If you have multiple authentication solutions Butler Auth can be used to support several (or all) of them.

For example, let’s assume Okta is the primary authentication provider in your company but you also use Google’s tools (GMail, Sheets, Docs etc).

Butler Auth can then be configured for both Okta and Google authentication, with the effect that users can use either service when logging into Sense.

Use a single user account for all access to QSEoW

Sometimes you want all access to Qlik Sense to happen via a specific user account.

Admittedly, this might not be a very common scenario. But consider a trade show or other event where people should be able to test some Qlik Sense based application - ideally without having to log in at all.

You could solve this by using a Qlik Sense license that allows for anonymous users - but that’s probably overkill if the purpose is a simple demo event.

Another option is to use Butler Auth to force all access to Sense to use a single Sense account.
Given Sense’s limits on number of simultaneous sessions, only a handful (or less) people can try that Sense app at once - but it might be good enough for this specific use case.

Another use case would be to show a dashboard on a set of monitors in the office.

January 2021 note: Given how rarely people are in offices nowadays and the non-existing nature of trade shows, the use cases above might be pretty theoretical during coming months/years…

1.4 - Versions

Features are added, bugs are fixed. How are Butler Auth versions set?

In the spirit of not copying information to several places, the version history is kept as annotations of each release on the GitHub release page.

Version numbers include up to 3 levels, for example version 4.6.2 (which is a fictitious version):

4 is the major version. It is increased when Butler Auth has added major new features, or in other ways changed in major ways. If following this principle, breaking changes should always result in a bumped major version.

6 is the minor version. This indicates a smaller update, when one or a few minor features have been added.

2 is the patch level. When individual bugs are fixed, these are released with an increased patch level.

Note 1: Major and minor updates usually include bug fixes too.
Note 2: If a version of 5.2 is mentioned, this implicitly means 5.2.0.

1.5 - Contribution guidelines

How to contribute to Butler Auth.

Butler Auth is an open source project, using the MIT license.

This means that all source code, documentation etc is available as-is, at no cost.

It however also means that anyone interested can - and is encouraged to - contribute to the project!

Butler Auth is developed in Node.js, with support from various NPM modules.
Specifically, most authentication providers are implemented using Passport.js.

We use Hugo to format and generate this documentation site and the Docsy theme for styling and site structure.
Hugo is an open-source static site generator that provides us with templates, content organisation in a standard directory structure, and a website generation engine. You write the pages in Markdown (or HTML if you want), and Hugo wraps them up into a website.

All submissions, including submissions by project members, require review.
We use GitHub pull requests for this purpose. Consult GitHub Help for more information on using pull requests.

Discussions

We use GitHub’s discussion boards to discuss ideas, features, issues and everything else relating to Butler Auth.

Contributing to Butler Auth and this documentation site

Butler Auth itself lives in https://github.com/ptarmiganlabs/butler-auth.

The doc site lives in https://github.com/ptarmiganlabs/butler-auth-docs.

Code reviews

All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult GitHub Help for more information on using pull requests.

Test your changes

As obvious as it might sound: Please test your proposed changes properly before submitting pull requests.

Creating an issue

If you’ve found a problem - or have a feature suggestion - with Butler Auth or this documentation site, but you’re not sure how to fix it yourself, please create an issue in the Butler Auth or Butler Auth docs repos. You can also create an issue about a specific doc page by clicking the Create project issue button in the top right hand corner of the page.

2 - Getting started

What you need to know to get Butler Auth off the ground.

Installation

Follow the installation instructions - they will guide through the setup process, including requirements and customisation.

Setup

Once everything is installed you need to edit the configuration file to suit your specific needs.

Try it out!

Feel free to browse through the examples to get an understanding of how Butler Auth can be used.
There are also Youtube videos showing Butler Auth in action.

2.1 - Choosing an authentication solution

Authentication is about ensuring people are who they claim to be. This can be done in many ways with their respective pros, cons and security concerns.

There isn’t really any right or wrong here.
What’s right for your company might be unacceptable for another company, and vice versa.

This page is intended to make you think and consider the options you have.

Commercial service or open source?

The authentication providers supported by Butler Auth generally belong to either of two categories:

  • Commercial identity and authentication providers such as Okta and Auth0.
    These companies have entire teams dedicated to creating secure solutions for their customers. But the transparency is limited or non-existing. They will for sure use open standards like OAuth 2.0, OpenID etc - but you will never know exactly what their specific implementations look like.
    In other words: You will never be able to audit the code responsible for your authentication flow - you have to trust that these companies know what they are doing.

  • Open source libraries provide full transparency. You can audit them if/when needed.
    The downside is that these libraries are sometimes developed by individuals or companies that no longer actively maintain them. Which in worst case could mean that new security issues are discovered in a standard authentication protocol, but the open source libraries are not quickly updated - or not updated at all.
    In this case you’d be using a library with security issues associated with it. While this is rare, it’s a real possibility.

Passport.js

Butler Auth relies heavily on the authentication strategies available via Passport.js.

This is an open source authentication library boasting 500+ various kinds of authentication strategies.

Now, there will be some duplicates (for example several different Passport.js strategies offering Google authentication) and most of those 500+ strategies will be rather obscure - with the associated risk of not being supported.
The big ones - Google, Microsoft, generic OAuth 2.0, Auth0, LDAP, OpenID etc - are generall well supported and kept up to date.
For that reason they are also used in Butler Auth.

Recommendation

So how should you reason if you have the luxury of deciding yourself what authentication solution to use?

  • If low cost and ease of setup is the main focus you should go with the big, established service providers. Google, Microsoft, GitHub, Amazon etc. By using open source authentication modules you won’t have any cost for the software or service.
    These are reasonably easy to set up and get working.

  • If you have high security requirements and prefer (or must use) open source, Keycloak is a good option.

    Keycloak can however be challenging to set up properly, at least if you also want to lock it down to meet specific security requirements. It’s like a Swiss army knife of authentication, with many, many tools in it…
    There is simply a risk of configuring it incorrectly and not achieve the desired security level as a result.

  • If you can accept some costs associated with authentication you could use one of the commercial services. With some of them you can still use Google/Microsoft/… authentication if so desired, but you offload that integration work to the service provider.

2.2 - Installing Butler Auth

How to install Butler Auth, including requirements and on what platforms it can be installed.

Given the cross platform nature of Node.js (which is the language Butler Auth is written in), Butler Auth can run on lots of different hardware platforms and operating systems.

It is therefore difficult to give detailed installation instructions for each possible installation scenario. This site thus tries to explain how to get started with Butler Auth in some of the most common scenarios.

Getting started

Sorry - there is no installer for Butler Auth.
You will need to work a bit on the command line to set things up.

It’s not as bad as it sounds though, the instructions here should help you to get started.

Prerequisites

Either you install a few pieces of software (most notably Node.js and some node modules), or you run Butler Auth in a Docker container.

Either way you also need to edit Butler Auth’s configuration file and provide certificates exported from Qlik Sense Enterprise.

2.2.1 - Choose a platform

On what platforms does Butler Auth run?

If you have access to or can set up a Docker runtime environment, this is by far the preferred way of running Butler Auth.

Installation is less error prone compared to installing Butler Auth as a Node.js app, you get all the benefits from the Docker ecosystem (monitoring of running containers etc), and upgrades to future Butler Auth ersions become trivial.

If you have access to a Kubernetes cluster, that is usually an even better option than Docker. Kubernetes can be daunting when first approached, but will give you superb reliability, failover and restarts if a server goes down or becomes unresponsive etc.

Rancher’s K3s is a great way to get started with Kubnernetes. Fully featured, well supported and a vibrant developer community.

2.2.2 - Installing Butler Auth in a Docker container

How to install Butler Auth as a Docker container.

Prerequisites for running Butler Auth in Docker:

What Comment
Qlik Sense Enterprise on Windows Mandatory. Butler Auth is developed with Qlik Sense Enterprise on Windows in mind.
Docker Mandatory. A Docker runtime environment on any supported platform. This means you can run Butler Auth on any platform where Docker is available, including Linux, Mac OS, Windows and most cloud providers. Kubernetes is also a great option for running Butler Auth!
InfluxDB Optional. A database for realtime information, used to store metrics around Butler’s own memory usage over time (if this feature is enabled).

Installation steps

The following steps give some guidance on how to get Butler Auth running on Docker.
Here Mac OS has been used, things will look different on Linux and Windows.

➜  ~ mkdir /Users/goran/butler-auth
➜  ~ cd /Users/goran/butler-auth
➜  butler-auth mkdir -p config/certificate
➜  butler-auth mkdir sessions
➜  butler-auth mkdir log
➜  butler-auth wget https://raw.githubusercontent.com/ptarmiganlabs/butler-auth/main/src/docker-compose.yaml
--2021-01-20 13:58:54--  https://raw.githubusercontent.com/ptarmiganlabs/butler-auth/main/src/docker-compose.yaml
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.128.133, 151.101.64.133, 151.101.192.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.128.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 754 [text/plain]
Saving to: ‘docker-compose.yaml’

docker-compose.yaml                                                   100%[========================================================================================================================================================================>]     754  --.-KB/s    in 0s

2021-01-20 13:58:54 (37.8 MB/s) - ‘docker-compose.yaml’ saved [754/754]

➜  butler-auth
➜  butler-auth cat docker-compose.yaml
# docker-compose.yml
version: '3.3'
services:
  butler-auth:
    image: ptarmiganlabs/butler-auth:1.0.0
    container_name: butler-auth
    restart: always
    ports:
      - "8081:8081"       # http/web server used to serve sample login forms included in Butler Auth
      - "8761:8761"       # REST API called by Qlik Sense Enterprise when users should be authenticated
    volumes:
      # Make config file and logs accessible outside of container
      - "./config:/nodeapp/config"
      - "./log:/nodeapp/log"
      - "./sessions:/nodeapp/sessions"
      - "/path/to/tls/cert:/nodeapp/config/tls"
    environment:
      - "NODE_ENV=production"
    logging:
      driver: json-file
      options:
        max-file: "5"
        max-size: "5m"
➜  butler-auth

At this point you should

  1. Export certificates from the Qlik Sense QMC. Export a full set of certificates in PEM format, with or without passwords on the certificates. If a password is used it must also be specified in Butler Auth’s config file.
  2. Copy the certificates to the ./config/certificate directory.
  3. Copy the template config file from the GitHub repository to the ./config directory, modify it as needed based on your system(s) and which Butler Auth features you want enabled.
    Rename it to for example production.yaml.
    You can actually name the config file anything, but its name has to match the NODE_ENV environment variable, as set it the docker-compose.yaml file.
  4. If using the local-file auth provider, you also need a corresponding YAML file where user info is stored. There is a template file in the GitHub repository.
  5. If using TLS to secure Butler Auth (you should!), the volumes entry /path/to/tls/cert:/nodeapp/config/tls in docker-compose.yaml must point to your TLS certificates.

When done, you should see something like this:

➜  butler-auth tree
.
├── config
│   ├── certificate
│   │   ├── client.pem
│   │   ├── client_key.pem
│   │   └── root.pem
│   ├── production.yaml
│   └── users.yaml
├── docker-compose.yaml
├── log
└── sessions

4 directories, 6 files
➜  butler-auth

At this point everything is ready and you can start the Butler Auth container using docker-compose (IP addresses and URLs have been slightly scrambled below):

➜  butler-auth docker-compose up
Creating network "butler-auth_default" with the default driver
Pulling butler-auth (ptarmiganlabs/butler-auth:1.0.0)...
1.0.0: Pulling from ptarmiganlabs/butler-auth
22f9b9782fc3: Already exists
072739d44e4f: Already exists
5111f27e9600: Already exists
dc22afea6082: Already exists
0ad0b403cda0: Already exists
bca65cadbc25: Already exists
c1e57ccc1a03: Already exists
2571476d0e73: Already exists
e3719000bb2c: Already exists
d09cb7e3b7d4: Pull complete
76d111860f8b: Pull complete
c30b9b6a8b26: Pull complete
e75f642798c7: Pull complete
5b06a9fb8f94: Pull complete
Digest: sha256:545e81b4a638cb2f50b7718723cd60528e91a237349429279a90928c95fa420f
Status: Downloaded newer image for ptarmiganlabs/butler-auth:1.0.0
Creating butler-auth ... done
Attaching to butler-auth
butler-auth    | 2021-01-19T06:22:18.070Z info: CONFIG: Influxdb enabled: true
butler-auth    | 2021-01-19T06:22:18.075Z info: CONFIG: Influxdb host IP: 1.2.3.4
butler-auth    | 2021-01-19T06:22:18.075Z info: CONFIG: Influxdb host port: 8086
butler-auth    | 2021-01-19T06:22:18.076Z info: CONFIG: Influxdb db name: butlerauth
butler-auth    | 2021-01-19T06:22:18.413Z info: AUTH-LOCALFILE: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.415Z info: AUTH-LOCALFILE: Loading user list.
butler-auth    | 2021-01-19T06:22:18.419Z info: AUTH-LOCALFILE: Successfully loaded users from file.
butler-auth    | 2021-01-19T06:22:18.420Z debug: AUTH-LOCALFILE: Users loaded from file: [
butler-auth    |   {
butler-auth    |     "username": "anna",
butler-auth    |     "fullName": "Anna Svenson",
butler-auth    |     "password": "aaa",
butler-auth    |     "comment": "Root admin user"
butler-auth    |   },
butler-auth    |   {
butler-auth    |     "username": "joe",
butler-auth    |     "fullName": "Joe Jonson",
butler-auth    |     "password": "bbb",
butler-auth    |     "comment": "Regular user"
butler-auth    |   }
butler-auth    | ]
butler-auth    | 2021-01-19T06:22:18.421Z info: AUTH-LDAP: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.421Z info: AUTH-GOOGLEOAUTH: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.422Z info: AUTH-FACEBOOK: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.423Z info: AUTH-MICROSOFT: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.424Z info: AUTH-OKTA: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.425Z info: AUTH-KEYCLOAK: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.425Z info: AUTH-AUTH0: Setting up endpoints.
butler-auth    | 2021-01-19T06:22:18.426Z debug: HEARTBEAT: Setting up heartbeat to remote: http://healthcheck.mycompany.com/ping/12345678-1234-1234-1234-b10b81583522
butler-auth    | 2021-01-19T06:22:18.428Z info: --------------------------------------
butler-auth    | 2021-01-19T06:22:18.428Z info: Starting Butler authenticator
butler-auth    | 2021-01-19T06:22:18.428Z info: Log level: debug
butler-auth    | 2021-01-19T06:22:18.428Z info: App version: 1.0.0
butler-auth    | 2021-01-19T06:22:18.428Z info: --------------------------------------
butler-auth    | 2021-01-19T06:22:18.458Z info: MAIN: REST server now listening on butler-auth:8761
butler-auth    | 2021-01-19T06:22:18.459Z info: MAIN: Web server now listening on butler-auth:8081
butler-auth    | 2021-01-19T06:22:18.478Z info: CONFIG: Found InfluxDB database: butlerauth
butler-auth    | 2021-01-19T06:22:18.597Z debug: HEARTBEAT: Sent heartbeat to http://healthcheck.mycompany.com/ping/12345678-1234-1234-1234-b10b81583522

What you see on your screen will depend on which Butler Auth version you are using and what features are enabled.

2.2.3 - Running Butler Auth as a native Node.js application

How to install Butler Auth as a Node.js application.

While Qlik Sense Enterprise is a Windows only system, Butler Auth runs on any OS where Node.js is available.
Butler Auth has been succesfully used using standard Node.js - during development and production - on Windows, Linux (Debian and Ubuntu tested) and Mac OS.

Running as Node.js app

Prerequisites:

What Comment
Sense Enterprise Mandatory. Butler Auth is developed with Qlik Sense Enterprise on Windows in mind.
Node.js Mandatory.
InfluxDB Optional. A database for realtime information, used to store metrics around Butler Auth’s own memory usage over time (if this feature is enabled).

Installation steps

  • Install node.js
    Butler Auth was developed and tested using the 64 bit version of Node.js. The most recent LTS (Long Term Support) version of Node.js is a good choice for running Butler. At time of this writing, Node.js 14.5 is used.

  • Decide where to install Butler Auth
    It is usually a good starting point to run Butler Auth on a Sense server.

    On the other hand, you might want to keep the Sense servers as clean as possible (with respect to software running on them). If that is a priority you should install Butler Auth on some other server. A small “utility” or “misc” server can often be useful for running various add-on services to Qlik Sense.

    The bottom line is that Butler Auth can run on any server, as long as Node.js is available and there is network connectivity to the actual Qlik Sense server(s).

  • Download Butler Auth
    Download the repository zip from the releases page file or clone the Butler Auth repository using your git tool of choice. Both options achieve the same thing, i.e. a directory such as d:\node\butler-auth, which is then Butler Auth’s root directory.

  • Install node dependencies
    From a Windows command prompt (assuming the Butler ZIP file/repository was extracted to d:\node\butler-auth):

    d:
    cd \node\butler-auth\src
    npm install
    

    This will download and install the Node.js modules used by Butler Auth.

  • Configuration
    Configuration of Butler Auth is done more or less the same way as configuring for Docker, i.e. get certificates from Qlik Sense Enterprise on Windows > store them in suitable location > refer to those cert files from production.yaml file etc.
    More details are then available in the on the Configuration pages.

2.3 - Setup

Everything you wanted to know about Butler Auth configuration but never dared to ask.

2.3.1 - Which config file to use

Butler Auth can be configured using different config files. Here you learn to control which one is used.

A description of the config file format is available here.

Select which config file to use

Butler Auth uses configuration files in YAML format. The config files are stored in the src/config folder.

Trying to run Butler Auth with the default config file (the one included in the files download from GitHub) will not work - you need to adapt it to your server environment.

The name of the config file matters. Butler Auth looks for an environment variable called “NODE_ENV” and then tries to load a config file named with the value found in NODE_ENV.

For example:

  • NODE_ENV=production

  • Butler will look for a config file config/production.yaml.

Setting environment variables

The method for setting environment variables varies between different operating systems:

On Windows:

set NODE_ENV=production

Mac OS or Linux

export NODE_ENV=production

If using Docker, the NODE_ENV environment varible is set in the docker-compose.yml file (as already done in the sample docker-compose file.)

2.3.2 - Configuration

Instructions for configuring the different parts of the Butler Auth config file.

2.3.2.1 - Logging

Logging can be done to disk and/or console, with customisable logging levels and location of log files.

What’s this?

Logging tells you what Butler Auth has done in the past.
Who logged in when, if you like.

Temporarily increasing logging verbosity can also be very useful when setting up new authentication providers.
Don’t forget to dial back the logging level once everthing works though!

Settings in config file

---
ButlerAuth:
  ...
  ...
  # Logging configuration
  logLevel: info      # Log level. Possible log levels are silly, debug, verbose, info, warn, error
  fileLogging: false  # true/false to enable/disable logging to disk file
  logDirectory: log   # Subdirectory where log files are stored. Absolute or relative path accepted.
  ...
  ...

2.3.2.2 - Heartbeats

Heartbeats provide a way to monitor that Butler Auth is running and working as intended.
Butler can send periodic heartbeat messages to a monitoring tool, which can then alert if Butler Auth hasn’t checked in as expected.

What’s this?

A tool like Butler Auth should be viewed as mission critical, at least if the Qlik Sense environment as such is considered mission critical.

But how can you know whether Butler Auth itself is working?
Somehow Butler Auth itself should be monitored.

Butler Auth (and most other tools in the Butler family) has a heartbeat feature.
It sends periodic messages to a monitoring tool, which can then alert if Butler hasn’t checked in as expected.

Healthchecks.io is an example of such as tool. It’s open source but also has a SaaS option if so preferred. Highly recommended!

More info on using Healthchecks.io with the Butler family can be found in this blog post.

Settings in main config file

---
Butler:
  ...
  ...
  # Heartbeats can be used to send "I'm alive" messages to any other tool, e.g. a infrastructure monitoring tool
  # The concept is simple: The remoteURL will be called at the specified frequency. The receiving tool will then know 
  # that Butler Auth is alive.
  heartbeat:
    enable: false                     # Enable/disable healthcheck pings
    remoteURL: http://my.monitoring.server/some/path/
    frequency: frequency: 60000       # Milliseconds
  ...
  ...

2.3.2.3 - Docker healthcheck

Docker has a concept of “health checks”, which is a way for Docker containers to tell the Docker runtime engine that the container is alive and well. Butler can be configured to send such health check messages to Docker.

Note: Sending health check messages is only meaningful when running Butler Auth as a Docker container.

Settings in main config file

---
Butler:
  ...
  ...
  # Docker health checks are used when running Butler Auth as a Docker container. 
  # The Docker engine will call the container's health check REST endpoint with a set interval to determine
  # whether the container is alive/well or not.
  # If you are not running Butler Auth in Docker you can safely disable this feature. 
  dockerHealthCheck:
    enable: false    # Control whether a REST endpoint will be set up to serve Docker health check messages
    port: 12398      # Port the Docker health check service runs on (if enabled)
  ...
  ...

2.3.2.4 - Uptime monitor

Butler Auth can optionally log how long it’s been running and how much memory it uses. The memory usage can also (optionally) be stored to an InfluxDB database, for later viewing/alerting in for example a Grafana dashboard.

What’s this?

In some cases - especially when investigating issues or bugs - it can be useful to get log messages telling how long Butler Auth has been running and how much memory it uses.

This feature is called “uptime monitoring” and can be enabled in the main config file.

The logging interval is configurable, as is the log level required for uptime messages to be shown.

The memory usage data can optionally be written to InfluxDB, from where it can later be viewed in Grafana.
If the specified InfluxDB database does not exist it will be created. The same is true for the retenion policy.

Select a reasonable retention policy and logging frequency!
You will rarely if ever need to know how much memory Butler Auth used a month ago… A retention policy of 1-2 weeks is usually a good start, with logging every few minutes.

Settings in main config file

---
Butler:
  ...
  ...
  # Uptime monitor
  uptimeMonitor:
    enable: false                    # Should uptime messages be written to the console and log files?
    frequency: 300000                # Milliseconds
    logLevel: info                   # Starting at what log level should uptime messages be shown?
    storeInInfluxdb: 
      enable: false
      hostIP: <IP or host name>
      hostPort: 8086
      auth:
        enable: false
        username: user_joe
        password: joesecret
      dbName: butlerauth
      instanceTag: DEV              # Tag that can be used to differentiate data from multiple Butler Auth instances
      # Default retention policy that should be created in InfluxDB when Butler Auth creates a new database there. 
      # Any data older than retention policy threshold will be purged from InfluxDB.
      retentionPolicy:
        name: 10d
        duration: 10d
  ...
  ...

2.3.2.5 - REST/web server

How to configre up the REST and web servers that Butler Auth manage.

What’s this?

Butler Auth exposes a REST server which Qlik Sense will call when a user connects to a Qlik Sense virtual proxy.
There are then different REST API endpoints for different authentication providers. The REST server is also responding to the callbacks that happen as part of for example an OAuth 2.0 authentication flow. When the authentication provider has given green light, that provider’s callback endpoint on the REST server is called.

Secondly, a http server is used to serve a sample web based login interface.
This web site is for inspiration only. It has hard coded URLs that need to be changed before it is useful in your own environment. Still, it can serve as a basis for your own, custom/branded login page for Qlik Sense.
Each authentication provider that rely on some kind of web interface for entering user name and password has a url property the main YAML config file (for example ButlerAuth.authProvider.ldap.url). Those property can be used to direct authentication requests to your own, custom login user interfaces.

The settings below control the behvaiour of those two servers.

Settings in main config file

---
ButlerAuth:
  ...
  ...
  # Server and https settings
  server:
    rest:                   # The REST server is the authentication server called by Qlik Sense.
      host: <FQDN>          # Hostname of the REST server. Would be container name when running under Docker, otherwise something like qliksenseauth.mydomain.com.
      port: 8761            # Port where the REST server will listen
      rateLimit:            # Used to limit number of authentication requests during a given time window. Used to prevent brute forcing attacks.
        enable: false       # Enable/disable rate limiting for this REST API. true/false.
        windowSize: 60000   # How long (milliseconds) is the time window we're capping # of logins for? Default 5 min if not specified.
        maxCalls: 100       # Max # of logins from Qlik Sense during time window above. Default 100 if not specified.
      tls:                  # Many 3rd party auth providers require the OAuth 2 server to use https. 
        enable: true        # Enable/disable https. While always recommended, https is strictly not needed for local file authentication, for example.
        cert: /path/to/certfile.cer    # TLS certificate file 
        key: /path/to/certfile.key     # TLS key file
        password:           # Passphrase for TLS key file, if used
    web:                    # The web/http server used to serve the sample login pages included in Butler Auth
      host: <FQDN>          # FQDN of the http server 
      port: 8081            # Port where the http server will listen
      tls:                  # Used to secure the http server with TLS. I.e. https.
        enable: true
        cert: /path/to/certfile.cer
        key: /path/to/certfile.key
        password: 
  ...
  ...

2.3.2.6 - Auth providers

How to configure the authentication providers.

What’s this?

A core concept of Butler Auth is that of authentication providers, or just providers.

A provider’s purpose is to offer a way to authenticate users.
Once users are authenticated they are forwarded to Qlik Sense.

Providers can be individually enabled and disabled, i.e. there are no dependencies between providers.
Likewise, there are no limitations on how many or which providers can be enabled at the same time.

Each provider has it’s own settings in the config file.
If new providers are added to Butler Auth they will need to be configured in the config file.

Settings in main config file

---
ButlerAuth:
  ...
  ...
  # Auth providers are responsible for authenticating users before they are forwarded to Qlik Sense Enterprise.
  authProvider:       
    localFile:                          # "Local file" provider reads user data from a file on disk
      enable: false                    
      url: https://<FQDN>:8081          # URL where login UI for this provider is available
      userDirectory: lab                # Qlik Sense user directory that will be used for the authenticated user
      userFile: ./config/users.yaml     # YAML file containing usernames and passwords

    ldap:                               # "LDAP" provider
      enable: false
      url: https://<FQDN>:8081          # URL where login UI for this provider is available
      userDirectory: lab                # Qlik Sense user directory that will be used for the authenticated user
      ldapServer:                       # Information about the LDAP server to authenticate against
        host: <ldap(s)://ldap.mydomain.com>    # Both normal (ldap://) and secure (ldaps://) LDAP is supported
        port: 636                       # Usually 389 for LDAP and 636 for LDAPS
        bindUser: '<domain\username>'   # Service account used to log into the LDAP server
        bindPwd: <password>             # Password of service account
        searchBase: '<dc=...,dc=...,dc=...>'    # Base path from which authentication attempts will start
        searchFilter: '(&(objectcategory=person)(objectclass=user)(|(samaccountname={{username}})(mail={{username}})))' # Filter used to get info about users in LDAP server
        tls: 
          # Settings here will override default TLS behaviour. 
          # Useful for example if your cert is for another domain wrt the host name of the LDAP server.
          # If a setting is empty it will simply be ignored by Butler Auth.
          # Necessary if the LDAP server isusing a self-signed certificate
          # Should point to a PEM coded CA certificate file.
          ca: 

    singleUser:                       # "Single user" provider
      enable: false
      userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
      userId: goran                   # A user that already exists in QLik Sense. All access to Sense will be done using this user.

    google:                           # "Google" OAuth2 provider
      enable: false
      userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
      userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
      clientId: <Client ID>
      clientSecret: <Client secret>

    facebook:                         # "Facebook" OAuth2 provider
      enable: false
      userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
      userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
      clientId: <Client ID>
      clientSecret: <Client secret>

    microsoft:                        # "Microsoft" OAuth2 provider
      enable: false
      userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
      userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
      clientId: <client ID>
      clientSecret: <Client>

    okta:                             # "Okta" provider
      enable: false
      userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
      userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
      clientId: <Client ID>
      clientSecret: <Client secret>
      oktaDomain: <Okta domain from Google admin console>  # E.q. https://myid-123456.okta.com'
      idp: 

    keycloak:                         # "Keycloak" provider
      enable: true
      userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
      userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
      clientId: <Client ID>
      clientSecret: <Client secret>
      host: <FQDN of Keycloak server> # E.g. https://keycloak.mydomain.com
      realm:                          # E.g. ptarmiganlabs
      authorizationURL: <URL>         # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/auth
      tokenURL: <URL>                 # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/token
      userInfoURL: <URL>              # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/userinfo

    auth0:                            # "Auth0" provider
      enable: true
      userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
      userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
      issuerBaseURL: <FQDN>           # E.g. mycompany.eu.auth0.com
      baseURL: <URL>                  # FQDN of Butler Auth, e.g. https://qliksenseauth.mycompany.com:8761'
      clientId: <Client ID>
      clientSecret: <Client secret>
  ...
  ...

2.3.2.7 - Qlik Sense

What’s this?

These settings tell Butler Auth where to find the certificates it needs to communicate with Qlik Sense Enterprise.

Settings in main config file

---
ButlerAuth:
  ...
  ...
  # Settings relating to Qlik Sense
  qlikSense:
    # Certificates to use when calling Sense APIs. Get these from the Certificate Export in QMC.
    certFile:
      # If running under Docker, use these paths:
      # clientCert: /nodeapp/config/certificate/client.pem
      # clientCertKey: /nodeapp/config/certificate/client_key.pem
      # clientCertCA: /nodeapp/config/certificate/root.pem
      # If running as a native Node.js app, point to where the cert files are stored:
      clientCert: /path/to/client.pem
      clientCertKey: /path/to/client_key.pem
      clientCertCA: /path/to/root.pem
      clientCertPassphrase: 
    ...
    ...

2.4 - Day 2 operations

How to run Butler Auth once its been set up.

Running Butler Auth

How to start and keep Butler Auth running varies depending on whether you are using Docker or a native Node.js approach.

Running as a Docker container

Starting Butler Auth is easy.
First configure the docker-compose.yml file as needed, then start the Docker container in interactive mode (with output sent to the screen). This is useful to ensure everything works as intended when first setting up Butler Auth.

docker-compose up

Once everything works as intended, hit ctrl-c to stop the service.
Then start it again in deameon (background) mode:

docker-compose up -d

From here on the Docker enviromment will make sure Butler is always running, including restarting it if it for some reason stops.

Running as native Node.js app

Starting Butler Auth as a Node.js task is easy too:

d:
cd \node\butler-auth\src
node index.js

It is of course also possible to put those commands in a command file (.bat on Windows, .sh etc on other platforms) file and execute that file instead.

Windows services & process monitors

As Butler Auth is the kind of service that (probably) should always be running on a server, it makes sense using a Node.js process monitor to keep it alive (if running as a Docker container you get this for free).

On Windows you can use the excellent Nssm tool to make Butler Auth run as a Windows Service, with all the benefits that follow (can be monitored using operations tools, automatic restarts etc).

If running Butler Auth as a Node.js app on Linux, PM2 and Forever are two good process monitors.

Monitoring Butler Auth

Once Butler Auth is running it’s a good idea to also monitor it. Otherwise you stand the risk of not getting notified if it for some reason misbehaves.

Butler Auth will log data on its memory usage to InfluxDB if

  1. The config file’s ButlerAuth.uptimeMonitor.enable and ButlerAuth.uptimeMonitor.storeInInfluxdb.enable properties are both set to true.
  2. The remaining InfluxDB properties of the config file are correctly configured.

Assuming everything is correctly set up, you can then create a Grafana dashboard showing Butler Auth’s memory use over time.
You can also set up alerts in Grafana if so desired, with notifications going to most IM tools and email.

The following metrics are logged to InfluxDB, in a measurement called butlerauth_memory_usage:

  • heap_used
  • heap_total
  • external
  • process_memory

Each measurement is also tagged with a tag called butlerauth_instance. This tag is set in the main config file and is used in complex environments to separate between different Butler Auth instances.

A Grafana dashboard can look like this. Note that one of the available metrics (external) is not used in this particular dashboard. It’s still logged to InfluxDB though.

alt text

There is a sample Grafana dashboard in Butler’s GitHub repo.

3 - Examples

Butler Auth in action!

3.1 - Auth providers

Examples of how the authentication providers can be configured.

Demo web page

Butler Auth includes a small demo web site that makes it easy to try the various authentication providers (assuming you have accounts with them, of course).

The site is just a single page with links to each authentication provider supported by Butler Auth:

Demo UI for all authentication providers

Note:
The demo site has hard coded links to a specific Qlik Sense Enterprise on Windows server.
This means you can view the demo site above, but when clicking the links you won’t be able to connect to the Sense server.

Instructions for customising the demo site are available here.

3.1.1 - Auth0

Configuring Auth0.

Auth0 is an interesting authentication provider in that they offer both a user directory service, but also “passthrough authentication” to other auth providers such as Google, GitHub, Microsoft etc.

It’s thus possible to set up Butler Auth to work with Auth0, and then via Auth0 get access to their entire list of supported auth providers.

Butler Auth configuration

The settings in the config file are:

auth0:                              # "Auth0" provider
    enable: true
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
    issuerBaseURL: <FQDN>           # E.g. mycompany.eu.auth0.com
    baseURL: <URL>                  # FQDN of Butler Auth, e.g. https://qliksenseauth.mycompany.com:8761'
    clientId: <Client ID>
    clientSecret: <Client secret>
Field Description
enable Enable or disable this authentication provider. true/false.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userIdShort The provider will return the user’s email address. If userIdShort is set to true, the @ character and email domain will be stripped from the email address returned by the provider. For example, “joe@company.com” would become just “joe”. true/false.
issuerBaseURL The URL pointing to Auth0’s service. You get this from Auth0. For Ptarmigan Labs (who’s located in Europe/EU), the URL could be ptarmiganlabs.eu.auth0.com.
baseURL URL to Butler Auth. For Ptarmigan Labs this could be https://qliksenseauth.ptarmiganlabs.net:8761
clientId Client ID from Auth0
clientSecret Client secret from Auth0

Auth0 configuration

These are the general steps to set up Auth0 for use with Butler Auth.

Create application

  1. Log in to your Auth0 dasboard (https://manage.auth0.com/dashboard).

  2. Go to the applications section, then create a new application. You can go through the step-by-step wizard, but it’s usually easier to just fill in the needed fields on the Settings tab. Auth0 applications

  3. Fill in the specifics of your application on the Settings tab. There are lots of fields here, the important ones are

    1. Name: Application’s name. “Qlik Sense Enterprise” or “Butler Auth” could be good names, but anything goes.
    2. Description: Not mandatory, but it’s a good idea to write down a few words what the Auth0 does and its intended use cases.
    3. Application Logo: If you want your users to see a logo when authentication, this is where it’s set.
    4. Application Type: Set to “Regular Web Application”.
    5. Token Endpoint Authentication Method: Set to “Post”.
    6. Allowed Callback URLs: This one is important from a security perspective. Set to the fully qualified domain name (FQDN) of Butler Auth, for example https://qliksenseauth.ptarmiganlabs.net:8761/auth/auth0/redirect. This is a list of URLs that Auth0 is authorized to call back to once the user has been successfully authenticated.
    7. The rest of the fields on the Settings tab can be left at default values. But do review then anyway - your specific use case may require some additional settings to be set! Auth0 create application

  4. Move on to the Connections tab. If you have previously set up “connections” (which is Auth0’s word for other authentication providers), this is where you enable them. Auth0 connections

3.1.2 - Facebook

Using Facebook Login with Butler Auth

Facebook offers authentication using OAuth 2.0.

Butler Auth configuration

The settings in the config file are:

facebook:                           # "Facebook" OAuth2 provider
    enable: false
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
    clientId: <Client ID>
    clientSecret: <Client secret>
Field Description
enable Enable or disable this authentication provider. true/false.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userIdShort The provider will return the user’s email address. If userIdShort is set to true, the @ character and email domain will be stripped from the email address returned by the provider. For example, “joe@company.com” would become just “joe”. true/false.
clientId Client ID from Facebook
clientSecret Client secret from Facebook

Facebook configuration

General steps to set up Facebook Login for use with Butler Auth.

Create application

  1. Log in to Facebook’s developer site https://developers.facebook.com.

  2. Go to the applications section, then create a new application:
    “Create App” > “Build Connected Experiences” > Enter app name and contact email > “Create App” > “Not a robot..”.

  3. Add the Facebook Login product to the newly created app:
    Click “Set Up” on the Facebook Login product > “Other” as platform.

  4. Open the basic settings:
    Facebook basic settings

    1. Set a “Display Name”.
    2. Enter a relevant “Contact Email” address.
    3. Enter a link for your “Privacy Policy URL”.
    4. Enter a link to your GDPR policy (or similar).
    5. Upload an app icon. It will be shown to users when authenticating via Facebook.
    6. Review remaining fields and fill in as needed for your specific use case.
  5. Copy the App ID and App Secret from the screen above to the Butler Auth config file.

3.1.3 - Google

Using Google credentials with Butler Auth.

Google offers authentication using OAuth 2.0.

Butler Auth configuration

The settings in the config file are:

google:                             # "Google" OAuth2 provider
    enable: false
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
    clientId: <Client ID>
    clientSecret: <Client secret>
Field Description
enable Enable or disable this authentication provider. true/false.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userIdShort The provider will return the user’s email address. If userIdShort is set to true, the @ character and email domain will be stripped from the email address returned by the provider. For example, “joe@company.com” would become just “joe”. true/false.
clientId Client ID from Google
clientSecret Client secret from Google

Google configuration

General steps to set up Google for use with Butler Auth.

Create application

  1. Log in to Google Cloud. The dashboard provides a good overview of your Google cloud assets.
  2. Go to the “Credentials” section (https://console.developers.google.com/apis/credentials) of the API & Services page. Make sure to select the correct project in the drop-down at the top of the page.
  3. Create a new client ID:
    1. “CREATE CREDENTIALS” (button at top) > “OAuth client ID” > Application typ “Web application”
    2. Enter desired name in the “Name” field.
    3. Add valid callback URIs. The one responsible for Butler Auth is https://<FQDN of Butler Auth>:<Butler Auth REST port>/oauth2callback. Note that Butler Auth’s REST API port can be changed in the main config file of Butler Auth. At least one URI is required.
      Click “Create”.
    4. Take note of the client ID and secret. Copy them to the corresponding fields in Buther Auth’s config file.
  4. Set up an OAuth consent screen that will be shown to users when they authenticate to Qlik Sense using their Google credentials.

3.1.4 - Keycloak

Using Keycloak with Butler Auth.

Butler Auth configuration

The settings in the config file are:

keycloak:                           # "Keycloak" provider
    enable: true
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
    clientId: <Client ID>
    clientSecret: <Client secret>
    host: <FQDN of Keycloak server> # E.g. https://keycloak.mydomain.com
    realm:                          # E.g. ptarmiganlabs
    authorizationURL: <URL>         # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/auth
    tokenURL: <URL>                 # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/token
    userInfoURL: <URL>              # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/userinfo
Field Description
enable Enable or disable this authentication provider. true/false.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userIdShort The provider will return the user’s email address. If userIdShort is set to true, the @ character and email domain will be stripped from the email address returned by the provider. For example, “joe@company.com” would become just “joe”. true/false.
clientId Client ID from Keycloak’s *realm* > Clients > *client* > Settings page.
clientSecret Client secret from Keycloak’s *realm* > Clients > *client* > Credentials page.
host Full URL to Keycloak
realm Keycloak realm to use.
authorizationURL See below for instruction on how to get this.
tokenURL See below for instruction on how to get this.
userInfoURL See below for instruction on how to get this.

Keycloak configuration

General steps to set up Keycloak for use with Butler Auth.

In the examples below Keycloak is available at http://qliksenseauth.ptarmiganlabs.net:8082.
This works for demonstration purposes, but in a production scenario https should be used.

  1. Log in to the Keycloak admin console. Keycloak

  2. If you don’t already have a Keycloak realm, create one via the menu in the upper left corner. Keycloak add realm

  3. Fill in the realm settings. The screen shots below only gives some guidance, you are STRONGLY encouraged to review all settings. The Frontend URL is the URL where Butler Auth will call Keycloak. Keycloak realm general

  4. Open the Clients menu on the left. Add a new one. Keycloak clients add

  5. Fill in the details of the new client. Keycloak client 1

    … and lower part of that page…
    The Valid Redirect URIs is a list of approved/allowed sources. Only calls originating from these URIs will be handled by this Keycloak realm/client.
    In our case, this is the callback URL of Butler Auth. Keycloak client 2

  6. The Credentials tab contains the Client secret that should be copied to Butler Auth. Keycloak client credentials

  7. The settings on the remaining tabs of the client configuration are used to fine-tune the authentication setup. The default values should work as a starting point though.

  8. If you don’t already have any users in Keycloak it’s easy to set up one for testing purposes. Open the Users menu on the left. Click the Add user button in upper right corner. Keycloak users

    Keycloak users add

Keycloak Identity Brokering

Keycloak has a cool feature similar to the one offered by Auth0, where you can use another, 3rd party identity provider for the actual authentication work.

For example, you can set up Butler Auth to use Keycloak (and have all the benefits offered by Keycloak), and then have Keycloak forward the authentication requqests to IdPs such as Microsoft, Google, Facebook, LinkedIn, Twitter, GitHub and others.

3.1.5 - LDAP

LDAP can be used both as a source for user directory data, but also to authenticate users.

Butler Auth configuration

The settings in the config file are:

ldap:                               # "LDAP" provider
    enable: false
    url: https://<FQDN>:8081        # URL where login UI for this provider is available
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    ldapServer:                     # Information about the LDAP server to authenticate against
        host: <ldap(s)://ldap.mydomain.com>    # Both normal (ldap://) and secure (ldaps://) LDAP is supported
        port: 636                   # Usually 389 for LDAP and 636 for LDAPS
        bindUser: '<domain\username>'       # Service account used to log into the LDAP server
        bindPwd: <password>         # Password of service account
        searchBase: '<dc=...,dc=...,dc=...>'    # Base path from which authentication attempts will start
        searchFilter: '(&(objectcategory=person)(objectclass=user)(|(samaccountname={{username}})(mail={{username}})))' # Filter used to get info about users in LDAP server
        tls: 
            # Settings here will override default TLS behaviour. 
            # Useful for example if your cert is for another domain wrt the host name of the LDAP server.
            # If a setting is empty it will simply be ignored by Butler Auth.

            # Necessary if the LDAP server isusing a self-signed certificate
            # Should point to a PEM coded CA certificate file.
            ca: 
Field Description
enable Enable or disable this authentication provider. true/false.
url Tells Butler Auth where it should send the user when it’s time to enter his/her username and password. A basic web page for entering LDAP credentials is included in Butler Auth, but for production scenarios you probably want to create your own login page.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
host Host where LDAP server is running. ldap://ldap.mydomain.com is insecure/not encryptet, ldaps://ldap.mydomain.com is secure. Use ldaps if possible.
port Port to use on LDAP server. Usually 636 for ldaps, 389 for ldap.
bindUser User to log in with on LDAP server. Usually a service account of some kind.
bindPwd Password for bindUser.
searchBase The base path from which authentication attempts will be done. For an Active Directory domain called sales at company mycompany.com it could be dc=sales,dc=mycompany,dc=com'
searchFilter Filter used to determine if a user exists in the LDAP server. The example above should be a good starting point for standard-install Active Directory servers.
ca If ldaps is used and the LDAP server is configured with proper certificates that use publicly recognizable certificate authorities, this ca section is not needed. If self-signed certificates are used you need to specify the CA certificate here for ldaps to work.

Using Butler Auth’s built-in login page

If you want to use the built-in login page to begin with, it’s configured like this:

  1. Let’s assume Butler Auth is hosted at https://butlerauth.company.com, with the http server set up to listen on port 8081.
    The demo web UI showing all the authentication providers is then available at https://butlerauth.company.com:8081/auth-providers.html.
  2. In order to use the demo login page you should set the ButlerAuth.authProvider.ldap.url to https://butlerauth.company.com:8081

Here is the built-in LDAP login page:

LDAP demo login page

LDAP configuration

Configuring the directory server (which Butler Auth talks to using the LDAP protocol) is beyond the scope of this site.

3.1.6 - Local file

Use a local file as your user directory.

Butler Auth configuration

The settings in the config file are:

localFile:                          # "Local file" provider reads user data from a file on disk
    enable: false                    
    url: https://<FQDN>:8081        # URL where login UI for this provider is available
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userFile: ./config/users.yaml   # YAML file containing usernames and passwords
Field Description
enable Enable or disable this authentication provider. true/false.
url Tells Butler Auth where it should send the user when it’s time to enter his/her username and password. A basic web page for entering local-file credentials is included in Butler Auth, but for production scenarios you probably want to create your own login page.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userFile A YAML file containing usernames and passwords.

Using Butler Auth’s built-in login page

If you want to use the built-in login page to begin with, it’s configured like this:

  1. Let’s assume Butler Auth is hosted at https://butlerauth.company.com, with the http server set up to listen on port 8081.
    The demo web UI showing all the authentication providers is then available at https://butlerauth.company.com:8081/auth-providers.html.
  2. In order to use the demo login page you should set the ButlerAuth.authProvider.localFile.url to https://butlerauth.company.com:8081

Here is the built-in local file login page:

Local file demo login page

Userfile format

The file containing user credentials is YAML-formatted:

users:
  - username: anna
    fullName: Anna Svenson
    password: aaa
    comment: Root admin user
  - username: joe
    fullName: Joe Jonson
    password: bbb
    comment: Regular user

3.1.7 - Microsoft

Using Microsoft credentials with Butler Auth.

Butler Auth configuration

The settings in the config file are:

microsoft:                          # "Microsoft" OAuth2 provider
    enable: false
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
    clientId: <client ID>
    clientSecret: <Client>
Field Description
enable Enable or disable this authentication provider. true/false.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userIdShort The provider will return the user’s email address. If userIdShort is set to true, the @ character and email domain will be stripped from the email address returned by the provider. For example, “joe@company.com” would become just “joe”. true/false.
clientId Client ID from Microsoft
clientSecret Client secret from Microsoft

Microsoft configuration

These are the general steps to set up Microsoft for use with Butler Auth.

  1. Log in to the Miceosoft Azure portal.

  2. Go to the App registrations page.

  3. The screen shots below show a minimum configuration - you should review all fields to make sure the configuration is correct for your specific use case.

    On the application overview tab you find the Client ID, among other things. Microsoft application overview

    On the Branding tab you can upload an image that’s shown when users authenticate. Microsoft application branding

    On the Authentication tab you set the Redirect URIs. This is the URL where Butler Auth is running, appended with “/auth/microsoft/redirect”. Microsoft application authentication

    On the Secrets tab you find the Client secret that should be copied to the Butler Auth config file. Microsoft application secrets

3.1.8 - Okta

Using Okta with Butler Auth.

Butler Auth configuration

The settings in the config file are:

okta:                               # "Okta" provider
    enable: false
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
    clientId: <Client ID>
    clientSecret: <Client secret>
    oktaDomain: <Okta domain from Google admin console>  # E.q. https://myid-123456.okta.com'
    idp: 
Field Description
enable Enable or disable this authentication provider. true/false.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userIdShort The provider will return the user’s email address. If userIdShort is set to true, the @ character and email domain will be stripped from the email address returned by the provider. For example, “joe@company.com” would become just “joe”. true/false.
clientId Client ID from Okta
clientSecret Client secret from Okta
oktaDomain The URL you get from Okta. Usually something like “sometext.okta.com
idp Can usually be left blank.

Okta configuration

These are the general steps to set up Okta for use with Butler Auth.
In the screen shots below Okta’s free tier is used - things might look different for you.

  1. Sign into Okta. Go to the Applications tab: Okta applications

  2. Create a new “Web” application and give it a good name: Okta new web app

    Fill in Name, Base URIs (which is the Butler Auth URL) and Login redirect URIs (which is Butler Auth’s Okta callback URL). Review the other fields to make sure they match your use case. Click Done. Okta new web app

  3. Add users as needed. Okta users

3.1.9 - Single user

Butler Auth configuration

The settings in the config file are:

singleUser:                         # "Single user" provider
    enable: false
    userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
    userId: goran                   # A user that already exists in Qlik Sense. All access to Sense will be done using this user.
Field Description
enable Enable or disable this authentication provider. true/false.
userDirectory The Qlik Sense Enterprise user directory that will be used once the user has been authenticated by the authentication provider.
userId Qlik Sense user ID that all logins will use.

3.2 - Customizing the demo site

Adapt the built-in web site to work with your own Sense server.

Butler Auth demo site

A single web page provides an easy way to try out the different auth providers:

Demo UI for all authentication providers

The demo site - how does it work?

Each auth provider included on the demo site has a link that takes the user to Qlik Sense. For example, clicking the Google icon the user will be sent to https://senseprod.ptarmiganlabs.net/ba-google.

senseprod.ptarmiganlabs.net is a Qlik Sense Enterprise on Windows server, with a virtual proxy called ba-google (hint: ba=butlerauth).

That virtual proxy has the usual settings plus a link to a “authentication module” that should be used.

Virtual proxy using Butler Auth for Google authentication

The authentication module is - surprise - part of Butler Auth. More specifically the REST API of Butler Auth has an endpoint named /auth/google.

With Butler Auth’s REST API being hosted at https://qliksenseauth.ptarmiganlabs.net:8761 (this is all set in the main config file), the full URL for the virtual proxy’s authentication module is https://qliksenseauth.ptarmiganlabs.net:8761/auth/google.

Customizing the demo site

The list below should be a good starting point if you want to customize the demo site to your own server/network/Qlik Sense environment.

Configure http server

Butler Auth’s build in web server is always enabled, but must be configured.
Given the config below the web server will be running at https://qliksenseauth.ptarmiganlabs.net:8081.

https is enabled using the specified certificate/key. In this case the certificate is not password protected (the password field is empty).

ButlerAuth:
    server:
        web:                        # The web/http server used to serve the sample login pages included in Butler Auth
            host: qliksenseauth.ptarmiganlabs.net   # Hostname of the http server. Would be container name when running under Docker. 
            port: 8081              # Port where the http server will listen
            tls:                    # Used to secure the http server with TLS. I.e. https.
                enable: true
                cert: /path/to/cert/cert.cer
                key: /path/to/cert.key
                password: 

Create Qlik Sense virtual proxies

You can have many virtual proxies in Qlik Sense, even if you have just a single Sense server.
Each virtual proxy implements exactly one authentication method, or uses anonymous access to Sense.

If you want to try all the auth providers offered by Butler Auth, you need to create one virtual proxy for each provider:

Qlik Sense virtual proxies used together with Butler Auth

An example of a virtual proxy configuration for Google authentication is found up above on this page.

Modify the demo site

The demo site is included in the GitHub repository and in the image on Docker Hub. It’s located at /src/html in the GitHub repository.

The html pages are reasonably basic, but a general understanding of html, css and Javascript is needed to understand how they work.

You must do some changes before using the demo site with your Sense server. Failing to do this will cause the authentication flows to fail, simply because the demo site won’t find your Sense server.

The needed changes are quite simple: Search for https://senseprod.ptarmiganlabs.net in all files in the demo site and replace that URL with the URL to your Sense server.

Other than that, the pages only use paths relative to the http server’s base URL, meaning that the pages should work in your Sense environment without any changes. You might want to change look-and-feel etc though - feel free to use the provided pages as inspiration!

3.3 - Butler Auth is observable

Monitoring Butler Auth, making sure it’s alive and well.

Heartbeats

Butler Auth has an optional heartbeat feature, which when enabled will call a specific URL with a configurable interval.

A typical scenario is to use a monitoring tool such as Healthchecks.io to ensure that the heartbeats arrive on schedule.
That tool can then alert if the heartbeats don’t arrive on time.
Healthchecks.io is available both as a Docker image for self-hosting and as a SaaS offering.

Configuration of heartbeats is described here.

Here is a self-hosted Heahlthcheck.io instance used to monitor the Butler family of tools: Healthchecks.io

Uptime monitor with metrics in InfluxDB

Another aspect of monitoring is to keep track of the internals of the service in question.

Butler Auth’s “uptime monitor” is an optional feature that can be enabled in the config file.

When enabled it will send metrics on how much memory Butler Auth uses to an InfluxDB database, as well as logging these metrics to the log files.
Logging to InfluxDB and log files can be individually enabled/disabled.
Once the metrics are in InfluxDB then can be viewed using Grafana:

Butler Auth memory usage visualized using Grafana

Docker healthcheck

The main config file has options for enabling Docker healthchecks.
If running Butler Auth in Kubernetes this feature can useful when setting up custom avaialability logic for K8s containers.

4 - Reference

Reference material for Butler Auth.

4.1 - Config file

Description of Butler Auth’s config file.

Main config file

The production_template.yaml config file looks like this:

ButlerAuth:
    # Logging configuration
    logLevel: info      # Log level. Possible log levels are silly, debug, verbose, info, warn, error
    fileLogging: false  # true/false to enable/disable logging to disk file
    logDirectory: log   # Subdirectory where log files are stored. Absolute or relative path accepted.

    # Heartbeats can be used to send "I'm alive" messages to any other tool, e.g. a infrastructure monitoring tool
    # The concept is simple: The remoteURL will be called at the specified frequency. The receiving tool will then know 
    # that Butler Auth is alive.
    heartbeat:
        enable: false
        remoteURL: http://my.monitoring.server/some/path/
        frequency: 60000                # Milliseconds

    # Docker health checks are used when running Butler Auth as a Docker container. 
    # The Docker engine will call the container's health check REST endpoint with a set interval to determine
    # whether the container is alive/well or not.
    # If you are not running Butler Auth in Docker you can safely disable this feature. 
    dockerHealthCheck:
        enable: false    # Control whether a REST endpoint will be set up to serve Docker health check messages
        port: 12398      # Port the Docker health check service runs on (if enabled)

    # Uptime monitor
    uptimeMonitor:
        enable: false                    # Should uptime messages be written to the console and log files?
        frequency: 300000                # Milliseconds
        logLevel: info                   # Starting at what log level should uptime messages be shown?
        storeInInfluxdb: 
            enable: false
            hostIP: <IP or host name>
            hostPort: 8086
            auth:
                enable: false
                username: user_joe
                password: joesecret
            dbName: butlerauth
            instanceTag: DEV              # Tag that can be used to differentiate data from multiple Butler instances
            # Default retention policy that should be created in InfluxDB when Butler creates a new database there. 
            # Any data older than retention policy threshold will be purged from InfluxDB.
            retentionPolicy:
                name: 10d
                duration: 10d

    # Server and https settings
    server:
        rest:                       # The REST server is the authentication server called by Qlik Sense.
            host: <FQDN>            # Hostname of the REST server. Would be container name when running under Docker, otherwise something like qliksenseauth.mydomain.com.
            port: 8761              # Port where the REST server will listen
            rateLimit:              # Used to limit number of authentication requests during a given time window. Used to prevent brute forcing attacks.
                enable: false       # Enable/disable rate limiting for this REST API. true/false.
                windowSize: 60000   # How long (milliseconds) is the time window we're capping # of logins for? Default 5 min if not specified.
                maxCalls: 100       # Max # of logins from Qlik Sense during time window above. Default 100 if not specified.
            tls:                    # Many 3rd party auth providers require the OAuth 2 server to use https. 
                enable: true        # Enable/disable https. While always recommended, https is strictly not needed for local file authentication, for example.
                cert: /path/to/certfile.cer    # TLS certificate file 
                key: /path/to/certfile.key     # TLS key file
                password:           # Passphrase for TLS key file, if used
        web:                        # The web/http server used to serve the sample login pages included in Butler Auth
            host: <FQDN>            # FQDN of the http server 
            port: 8081              # Port where the http server will listen
            tls:                    # Used to secure the http server with TLS. I.e. https.
                enable: true
                cert: /path/to/certfile.cer
                key: /path/to/certfile.key
                password: 

    # Auth providers are responsible for authenticating users before they are forwarded to Qlik Sense Enterprise.
    authProvider:
        localFile:                          # "Local file" provider reads user data from a file on disk
            enable: false                    
            url: https://<FQDN>:8081        # URL where login UI for this provider is available
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userFile: ./config/users.yaml   # YAML file containing usernames and passwords

        ldap:                               # "LDAP" provider
            enable: false
            url: https://<FQDN>:8081        # URL where login UI for this provider is available
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            ldapServer:                     # Information about the LDAP server to authenticate against
                host: <ldap(s)://ldap.mydomain.com>    # Both normal (ldap://) and secure (ldaps://) LDAP is supported
                port: 636                   # Usually 389 for LDAP and 636 for LDAPS
                bindUser: '<domain\username>'       # Service account used to log into the LDAP server
                bindPwd: <password>         # Password of service account
                searchBase: '<dc=...,dc=...,dc=...>'    # Base path from which authentication attempts will start
                searchFilter: '(&(objectcategory=person)(objectclass=user)(|(samaccountname={{username}})(mail={{username}})))' # Filter used to get info about users in LDAP server
                tls: 
                    # Settings here will override default TLS behaviour. 
                    # Useful for example if your cert is for another domain wrt the host name of the LDAP server.
                    # If a setting is empty it will simply be ignored by Butler Auth.

                    # Necessary if the LDAP server isusing a self-signed certificate
                    # Should point to a PEM coded CA certificate file.
                    ca: 

        singleUser:                         # "Single user" provider
            enable: false
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userId: goran                   # A user that already exists in Qlik Sense. All access to Sense will be done using this user.

        google:                             # "Google" OAuth2 provider
            enable: false
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
            clientId: <Client ID>
            clientSecret: <Client secret>

        facebook:                           # "Facebook" OAuth2 provider
            enable: false
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
            clientId: <Client ID>
            clientSecret: <Client secret>

        microsoft:                          # "Microsoft" OAuth2 provider
            enable: false
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
            clientId: <client ID>
            clientSecret: <Client>

        okta:                               # "Okta" provider
            enable: false
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
            clientId: <Client ID>
            clientSecret: <Client secret>
            oktaDomain: <Okta domain from Google admin console>  # E.q. https://myid-123456.okta.com'
            idp: 

        keycloak:                           # "Keycloak" provider
            enable: true
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
            clientId: <Client ID>
            clientSecret: <Client secret>
            host: <FQDN of Keycloak server> # E.g. https://keycloak.mydomain.com
            realm:                          # E.g. ptarmiganlabs
            authorizationURL: <URL>         # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/auth
            tokenURL: <URL>                 # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/token
            userInfoURL: <URL>              # E.g. https://keycloak.mydomain.com/auth/realms/<myrealm>/protocol/openid-connect/userinfo

        auth0:                              # "Auth0" provider
            enable: true
            userDirectory: lab              # Qlik Sense user directory that will be used for the authenticated user
            userIdShort: true               # If true, the email domain will be removed. I.e. "joe.smith@domain.com" will be changed to "joe.smith".
            issuerBaseURL: <FQDN>           # E.g. mycompany.eu.auth0.com
            baseURL: <URL>                  # FQDN of Butler Auth, e.g. https://qliksenseauth.mycompany.com:8761'
            clientId: <Client ID>
            clientSecret: <Client secret>

    # Settings relating to Qlik Sense
    qlikSense:
        # Certificates to use when calling Sense APIs. Get these from the Certificate Export in QMC.
        certFile:
            # If running under Docker, use these paths:
            # clientCert: /nodeapp/config/certificate/client.pem
            # clientCertKey: /nodeapp/config/certificate/client_key.pem
            # clientCertCA: /nodeapp/config/certificate/root.pem

            # If running as a native Node.js app, point to where the cert files are stored:
            clientCert: /path/to/client.pem
            clientCertKey: /path/to/client_key.pem
            clientCertCA: /path/to/root.pem
            clientCertPassphrase: 

Comments

  • The default location for cert/key exports is (assuming a standard install of Qlik Sense) C:\ProgramData\Qlik\Sense\Repository\Exported Certificates\<name specified during certificate export>

    The files needed by Butler Auth are client.pem, client_key.pem and root.pem.

4.2 - Passport.js

Butler Auth uses Passport.js for most authentication providers.

Passport.js

Passport.js is an open source library focusing on authentication.

From their own site:

Passport is authentication middleware for Node.js. Extremely flexible and modular, Passport can be unobtrusively dropped in to any Express-based web application. A comprehensive set of strategies support authentication using a username and password, Facebook, Twitter, and more.

Butler Auth uses Passport.js for many (but not all) authentication strategies.

Given that Passport.js uses a consistent interface for all authentication strategies it’s usually quite easy to add additional authentication providers to Butler Auth.

4.3 - Images & artwork attribution

Shoutout to these great creators for their excellent images and artwork!

Images

Cover page

Original by Jon Moore on Unsplash.
Some editing done before using it on this site.

5 - Security considerations

Security is important! Keep these things in mind when deploying Butler Auth.

Security is a whole field in its ownn.
What’s considered secure in one company might be considered insecure in another.

It’s a good idea to review your tools and services every now and then, for example making sure they are updated to include the latest secutity patches etc.

When in doubt, be paranoid.

Security considerations

  • Configure the firewall on the server where Buter Auth is running to only accept connections from IPs that matter. While convenient and tempting to leave servers open with respect to network traffic, it’s usually a very bad idea. Reduce the attack vectors whenever possible.

  • Butler Auth uses various Node.js modules from npm. If concerned about security, you should review these dependencies and decide whether there are issues in them or not.

  • Same thing with Butler Auth itself - while efforts have been made to make it secure, you need to decide for yourself whether the level of security is enough for your use case.

    Butler is continuously checked for security vulnerabilities by using GitHub security audit, Snyk, npm audit and other tools.

    That said, all software - including Butler Auth - has bugs and security issues.

  • Once again: YOU are responsible for determining if Butler Auth meets YOUR security requirements. The legal text is found in the MIT license.

Butler Auth talking to Qlik Sense

Butler Auth uses https for all communication with Sense, using Sense’s certificates for authentication.

6 - Legal stuff

Information om licenses, personal integrity and more.

License

Butler is distributed under the MIT license.

MIT License

Copyright (c) 2020-2021 Göran Sander

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Data collection

This documentation site was built using Hugo and consists of static web pages hosted on GitHub Pages.

GitHub probably keep log files for GitHub Pages, your visit to this documentation site is thus likely to be recorded there.

Google Analytics

Google Analytics is used to track general site usage.

Aggregated Google Analytics data may be used to determine, and in some cases publicly communicate, how popular the site is.
Examples of aggregated metrics are how many users have visited the site, from where in the world they accessed the site, which specific pages are most visited etc.

No detailed Google Analytics data for this site will be shared with any third parties.