Configure a tenant

Configure a tenant

In this tutorial, you are going to configure a tenant using Qlik Cloud management APIs so you can automate the process of analytics delivery to your end customers.

Sections

Code examples

Complete script examples for configuring a tenant using qlik-cli, curl, and Python are available here.

Prerequisites

Variable substitution

Throughout this tutorial, variables will be used to communicate value placement. The variable substitution format is <VARIABLE_NAME>. Here is a list of variables referred to in this tutorial.

VariableDescription
<CLIENT_ID>The client ID for an OAuth client, specific to the region you're sending requests to.
<CLIENT_SECRET>The client secret for the specific OAuth <CLIENT_ID>.
<TARGET_TENANT>The domain for the tenant you are configuring. Equivalent to tenant.<REGION>.qlikcloud.com.
<TARGET_TENANT_ID>The Qlik Cloud id of the tenant that you are configuring.
<TARGET_ACCESS_TOKEN>A bearer token for authorizing https requests to the <TARGET_TENANT>.
<REGION>The region identifier for the Qlik Cloud region that you're sending requests to. Examples include ap for Australia, eu for Ireland, sg for Singapore and us for North America.
<KEY_ID>A value you provide as the ID for the public certificate that you create the JWT IdP with, for example myportal. This ID value will also be required when making requests against this IdP.
<PUBLIC_CERTIFICATE>The body of your public certificate, which is used for creating the JWT IdP. Any requests against this IdP will need to be signed by the corresponding private certificate.
<ISSUER>A value that you provide as the issuer for the public certificate, for example https://myportal. This issuer value will also be required when making requests against this IdP.
<SHARED_SPACE_NAME>The space name for the shared space you will use as the staging space when deploying content. Note that this cannot be the same as the <MANAGED_SPACE_NAME> as all space names should be unique.
<SHARED_SPACE_ID>The Qlik Cloud id for <SHARED_SPACE_NAME>.
<MANAGED_SPACE_NAME>The space name for the managed spaces that you will use as the production space where users will consume content. Note that this cannot be the same as the <SHARED_SPACE_NAME> as all space names should be unique.
<MANAGED_SPACE_ID>The Qlik Cloud id for <MANAGED_SPACE_NAME>. <MANAGED_SPACE_NAME>
<GROUP_ID_TO_BE_ASSIGNED>The Qlik Cloud id for the group that you're giving access to the <MANAGED_SPACE_NAME> managed space.

Quick start

If you want to dive right into the code, all of the commands in this tutorial are available on the Qlik open source software github repository. Example commands are provided in multiple formats including Python, cURL, and qlik-cli.

1 Configure entitlement and provisioning settings

There are several tenant-level settings that you may want to configure before allowing end customers to access embedded analytics.

Enable auto creation of groups

Security in Qlik Cloud can be applied to both users and groups. Using groups to secure access to content and resources simplifies access management by allowing an identity provider outside of Qlik to manage user access to Qlik resources using group membership. As group membership changes, Qlik automatically picks up the changes and ensures that users can only access content and resources according to their group memberships.

To enable group management on a tenant, access the /groups/settings endpoint and set the autoCreateGroups property to true to permit group creation on user login, and the syncIdpGroups property to true if you are using a compatible interactive Identity Provider and wish groups to be synchronized:

curl -L "https://<TARGET_TENANT>/api/v1/groups/settings" \
-X PATCH \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Content-type: application/json" \
-H "Accept: application/json" \
-d '[{"op": "replace", "path": "/autoCreateGroups", "value": true},{"op": "replace", "path": "/syncIdpGroups", "value": true}]'

The response from this request is an http 204 updated status code. There are no additional details provided in the response.

Set user entitlement assignment behavior

You can entitle a user either as an analyzer or a professional user in the tenant.

  • The analyzer entitlement allows a user to consume content and resources they are assigned to on the tenant.

  • A professional entitlement adds creator and self-service capabilities to users.

In both cases, this entitlement provides access to content in the tenant. Tenant roles grant the entitled user additional capabilities in the tenant. Space permissions and roles allow further refinement to the content users and groups access depending on the location of the content in the tenant.

Note: Learn more about the different user entitlements for Qlik Cloud here.

To enable a tenant to automatically set users with the analyzer entitlement, send a request to the /licenses/settings endpoint to set the autoAssignProfessional property to false and the autoAssignAnalyzer to true:

curl -L "https://<TARGET_TENANT>/api/v1/licenses/settings" \
-X PUT \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Content-type: application/json" \
-H "Accept: application/json" \
-d '{"autoAssignProfessional":false,"autoAssignAnalyzer":true}'

2 Configure an identity provider

Obtain the tenant ID

To create an identity provider connection between your host application and the Qlik Cloud tenant, you need the tenant id to complete the configuration. To obtain the tenant id, send a request to the /users API:

curl -L "https://<TARGET_TENANT>/api/v1/users/me" \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json"

The JSON response includes a tenantId attribute, which you should store for later use as <TARGET_TENANT_ID>.

{
    "id": "62d8fce9b9f47dc69f17cf0a",
    "tenantId": "<TARGET_TENANT_ID>",
    "clientId": "00cbb22c600e823ed278d5e3d976f85a",
    "status": "active",
    "subject": "qlikbot\\00cbb22c600e823ed278d5e3d976f85a",
    "name": "US OAuth Client",
    "roles": [
        "TenantAdmin"
    ],
    "assignedRoles": [
        {
            "id": "608050f750afab80bd53586d",
            "name": "TenantAdmin",
            "type": "default",
            "level": "admin"
        }
    ],
...

Configure authorization using JSON web tokens

JSON web tokens, or JWTs as they are commonly referred, are a good option for embedded and integration use cases with Qlik because they allow users to authorize access to a tenant and consume content without encountering additional authentication dialogs.

Note: If you plan on using an interactive identity provider to authenticate the user to the tenant, please refer to the guide to add an interactive user to a tenant.

JWT authorization requires these steps to properly authorize users to a tenant:

  • A signing certificate key pair to encrypt and decrypt the JWT. Review this guide if you do not already have a public and private key pair to sign JWTs.
  • An active JWT authorization configuration in the tenant.
  • Code to generate JWTs that your application will send to the tenant to authorize users. You can learn more about the proper JWT format to send to a tenant here.

Adding a JWT authorization configuration to a tenant requires the public key certificate from the signing key pair in string format with a new line \n delimiter for each line in the certificate string.

Here's an example payload to create an JWT authorization identity provider:

{
  "active": true,
  "interactive": false,
  "protocol": "jwtAuth",
  "provider": "external",
  "tenantIds": ["<TARGET_TENANT_ID>"],
  "description": "JWT IdP for deferred authentication to my application",
  "options": {
    "issuer": "<ISSUER>",
    "staticKeys": [
      {
        "kid": "<KEY_ID>",
        "pem": "<PUBLIC_CERTIFICATE>"
      }
    ]
  }
}

To add a JWT authorization configuration to a tenant, make a request to the /identity-providers API:

curl -L "https://<TARGET_TENANT>/api/v1/identity-providers" \
-X POST \
-H 'Authorization: Bearer <TARGET_ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
      "tenantIds": ["<TARGET_TENANT_ID>"],
      "provider": "external",
      "protocol": "jwtAuth",
      "interactive": false,
      "active": true,
      "description": "JWT IdP for deferred authentication to my application",
      "options": {
        "jwtLoginEnabled": true,
        "issuer": "<ISSUER>",
        "staticKeys": [
          {
            "kid": "<KEY_ID>",
            "pem": "<PUBLIC_CERTIFICATE>"
          }
        ]
      }
    }'

Note that the issuer and kid values you configure the IdP with will be needed for creating signed JWTs to be accepted by this configuration.

An example JSON response:

{
  "id": "62a35a55d9b89de8948a6429",
  "tenantIds": ["<TARGET_TENANT_ID>"],
  "provider": "external",
  "protocol": "jwtAuth",
  "interactive": false,
  "active": true,
  "options": {
    "jwtLoginEnabled": true,
    "issuer": "<ISSUER>",
    "staticKeys": [
      {
        "kid": "<KEY_ID>",
        "pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
      }
    ]
  },
  "created": "2022-06-10T14:51:01.042Z",
  "lastUpdated": "2022-06-10T14:51:01.042Z",
  "description": "JWTAuth IdP",
  "clockToleranceSec": 5
}

3 Add groups to the tenant

Groups will be used to control access to the spaces that host your content. Adding groups to a tenant and assigning them to spaces before any users log in ensures that users only have access to content based upon their group membership.

Groups are created from the groups field when using a JWT authorization session. In the following example the groups Admin, Finance, Marketing, and Sales are created - if no groups with those names already exist - when a user authorizes to the tenant with the properly formatted JWT.

Note: In this example, you will set the subject (sub) to tmpgroupprovisioning, however the only recommendation is that this is unique, as once you've provisioned the groups, you can remove this user. Also note that groups are not tied to a realm - any IdP on the platform will match groups on only the group name.

const payload = {
  "jti": uid.sync(32), // 32 bytes random string
  "sub": "tmpgroupprovisioning",
  "subType": "user",
  "name": "user name",
  "email": "username@example.com",
  "email_verified": true,
  "groups": ["Admin", "Finance", "Marketing", "Sales"],
};

You can learn more about the JSON object payload format in the JWT authorization tutorial. The create_group function in the tenant_configure.sh provides an example of how to use JWT authentication to create groups.

Once groups are seeded on the tenant, you are going to need the id of the group you want to assign membership to on a space. To obtain a list of group metadata, use the /groups API:

curl -L "https://<TARGET_TENANT>/api/v1/groups" \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json"

The JSON response will be a list of groups and their associated metadata:

{
  "links": {"..."},
  "data": [
    {
      "id": "507f191e810c19729de860ea",
      "tenantId": "<TARGET_TENANT_ID>",
      "name": "Admin",
      "createdAt": "2021-03-21T17:32:28.000Z",
      "lastUpdatedAt": "2021-03-22T10:01:02.000Z",
      "status": "active",
      "assignedRoles": ["..."],
      "links": {"..."}
    },
  ...
}

Record the id of the group or groups that you are going to assign as a member to a space.

4 Create spaces in a tenant

A space allows you to define access control rules based on users or groups for the content contained within the space. There are three types of spaces in a tenant: personal, shared, and managed spaces.

Personal spaces reference content only the owner can access. They are not used in embedded use cases.

Shared spaces enable multiple users to collaborate on content creation. Put another way, shared spaces are the main branch for the analytics content deployed to a tenant.

Managed spaces represent the release area for analytics content. When content is published to a managed space, the main content, business logic, and content code cannot be manipulated.

Access to spaces and their content can be provided to named users in a tenant or through group membership. To learn more about spaces, see Working in spaces.

Implementing a shared space for staging deployed content and a managed space to support release consumption is a good design pattern for embedded analytics. Here's how to programmatically create spaces and set access control on them.

Create the shared space

Creating a shared space uses the /spaces API. The request for space creation requires a name for the space and a type for the space, which is either shared or managed. You may add a description for the space in this request using the description attribute.

curl -L "https://<TARGET_TENANT>/api/v1/spaces" \
-X POST \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "<SHARED_SPACE_NAME>", "description": "none", "type": "shared"}'

The JSON response when a space is created on a tenant includes metadata describing the access control available on the space. Make note of the space id as <SHARED_SPACE_ID> as you may need this later to assign groups and permissions.

{
  "id": "<SHARED_SPACE_ID>",
  "type": "shared",
  "ownerId": "00cbb22c600e823ed278d5e3d976f85a",
  "tenantId": "<TARGET_TENANT_ID>",
  "name": "<SHARED_SPACE_NAME>",
  "description": "none",
  "meta": {
    "actions": ["create", "delete", "read", "update"],
    "roles": [],
    "assignableRoles": ["consumer", "dataconsumer", "facilitator", "producer"]
  },
  "links": {"..."},
  "createdAt": "2022-06-17T12:55:11.574Z",
  "createdBy": "00cbb22c600e823ed278d5e3d976f85a",
  "updatedAt": "2022-06-17T12:55:11.574Z"
}

By default, the creator of a space has full access to that space. As this use case leverages the shared space as a staging area for your content prior to publishing to the managed space, you will not assign any additional users or groups at this stage. This is because the API user will be the only user accessing the space, and as that user created the space, it already has full access.

Create the managed space

Creating a managed space uses the same /spaces API with the same format as the shared space request, but the type value sent in the request is managed.

curl -L "https://<TARGET_TENANT>/api/v1/spaces" \
-X POST \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "<MANAGED_SPACE_NAME>", "description": "none", "type": "managed"}'

The JSON response when you create a managed space is exactly the same as a shared space, but with slightly different metadata including the type set to managed.

{
  "id": "<MANAGED_SPACE_ID>",
  "type": "managed",
  "ownerId": "00cbb22c600e823ed278d5e3d976f85a",
  "tenantId": "<TARGET_TENANT_ID>",
  "name": "<MANAGED_SPACE_NAME>",
  "description": "none"
}

Record the id attribute of the managed space as <MANAGED_SPACE_ID> for adding a group to the space.

Add a group to a managed space with the consumer role

Access control in spaces is set by adding members (users or groups) to the space and assigning them permissions tied to roles.

Note: Some space permissions may also depend on the user also having the appropriate license allocated, and the user or group having any specific roles assigned.

To provide a group whose users have permission to act as a consumer on a managed space you need:

  • The id of the group or groups you want to assign permissions (<GROUP_ID_TO_BE_ASSIGNED>).
  • The id of the managed space to assign the group (<MANAGED_SPACE_ID>).

Add a group and assign it a role on the managed space

Assigning a group and the role permissions of that group to a space uses the /assignments endpoint. The JSON payload for the request requires type, assigneeId, and roles attributes. The assigneeId attribute value should be the group id. In this example you will set the consumer role, which permits the specified group the ability to consume analytics, but not any editing or self-service capabilities.

{
  "type": "group",
  "assigneeId": "<GROUP_ID_TO_BE_ASSIGNED>",
  "roles": ["consumer"]
}

The request path contains the id of the managed space that you created in the previous step.

curl -L "https://<TARGET_TENANT>/api/v1/spaces/<MANAGED_SPACE_ID>/assignments" \
-X POST \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"type": "group", "assigneeId": "<GROUP_ID_TO_BE_ASSIGNED>", "roles": ["consumer"]}'

The JSON response from the tenant confirms the assignment of the group to the managed space was successful.

{
  "id":"626ff52f7ca0dba484332c21",
  "type":"group",
  "assigneeId":"<GROUP_ID_TO_BE_ASSIGNED>",
  "roles":["consumer"],
  "spaceId":"<MANAGED_SPACE_ID>",
  "tenantId":"<TARGET_TENANT_ID>",
  "createdAt":"2022-05-02T15:13:51.12Z",
  "createdBy":"00cbb22c600e823ed278d5e3d976f85a",
  "updatedAt":"2022-05-02T15:13:51.12Z",
  "links":{"..."}
}

Next steps

With your tenant, IdP, and spaces ready to go, the stage is set for deploying content to your tenant.

Was this page helpful?