This is a consolidated version of the technical documentation of Convier.

File: API sources

API sources

Convier can integrate with most JSON-based APIs. Reach out to support@convier.com if you need assistance configuring a particular source.

Supported authentication schemes:

JSON API

Example API integration

OData API

Odata integration

Odata data

File: Introduction

Technical Introduction to Convier

Convier is a webapp served by a Java HTTP server that runs as a single Docker container within your organization’s environment, e.g., as an App Service or Virtual Machine in Azure or on-premises using providers like VMware or Citrix. No data leaves your network, and Convier does not require to store or copy any data to operate: all data is fetched from your existing databases and services on demand. Data is stored together with saved reports. Reports, if configured, are stored in your existing CRM, or in a database of your choice. Convier also does not require a database server, as configuration is stored locally. Convier runs in your existing Azure tenant/organization or equivalent.

Getting Started

Getting started with Convier consists of three steps:

Resources from Convier are ready to assist with all three steps, including training users once the system is up and running.

Installation Patterns

The preferred way to install Convier is as an App Service or Virtual Machine that can be accessed directly from employee laptops and from within the company intranet.

For user authentication, the preferred method is Single Sign-On (SSO) with OIDC, for example, Microsoft 365 / Entra ID. Convier can run with an embedded OIDC provider for user authentication and authorization, but that is not recommended.

Convier has three different release tracks with different update intervals:

It is common to create a User Acceptance Testing instance that follows the stable-staging track. stable-staging normally gets updated one week before stable, which gives time to perform testing when necessary.

System Requirements

Convier is designed to run with minimal resources within a Docker container. It consists of a server component and a browser-based web app that is provided to users by the server.

Server

Hardware

The primary requirement is a physical or virtual machine capable of running Docker. A Linux host is preferred but not required. The Docker container will use storage mounted on the hardware, or a provided database, to persist configuration.

Resources

The estimated required resources depend on the intensity of use and the amount of data being processed.

Concurrent Users RAM CPU Cores Disk Space
1 - 2 4 2 4
2 - 10 8 4 8
11 - 30 16 8 16
31 - 50 20 16 24

Client

Requirements for the hardware/laptop users accessing the Convier web application:

The web browser must allow cookies for Convier to maintain user sessions.

Security Architecture

A high-level overview of the application architecture with required connection points:

image

Inbound

Outbound

Installation

Installation in Azure (Preferred)

See Running as an App Service in Azure

Manual Installation

Make sure you have docker installed: https://www.docker.com/ and optionally docker-compose plugin.

Log in to Convier Docker registry

docker login convier.azurecr.io

You will be asked for credentials. Get in touch with us if you don’t have these.

Run

docker run -p "0.0.0.0:80:14445" \
  -v ./data/app:/opt/convier/data \
  -e JDBC_CONNECTION_STRING='jdbc:sqlite:/opt/convier/data/internal.db' \
  convier.azurecr.io/convier:stable

With docker-compose.yml

version: '2'

services: 
  convier:
    image: convier.azurecr.io/convier:stable
    container_name: convier
    restart: always
    
    ports:
      - 0.0.0.0:80:14445

    volumes:      
      - ./data/app:/opt/convier/data

    environment:
      - JDBC_CONNECTION_STRING=jdbc:sqlite:/opt/convier/data/internal.db

Then run:

docker-compose up -d

Check logs:

docker compose logs -f convier

Health check

A health check endpoint is available at /convier/ping without authentication. It returns an empty HTTP 200 response. This endpoint is also the most relevant for readiness/liveness checks in a Kubernetes environment.

High availability / Scaling

The Convier application supports horizontal scaling, but for session management it is required that the load balancer supports session pinning to make sure that requests from a single user are directed to the a single instance.

Upgrade

Upgrades to Convier do require manual migrations. Normal downime during a single instance upgrade is between 30 seconds and 300 seconds.

docker compose pull && docker compose up -d

Audit logging

See Logging and Auditing

Backup

As Convier stores no data, only the configuration database needs to be backed up. When running an App Service with a persisted home folder, this backup is by default performed automatically.

Data Privacy

Convier stores no customer data, which limits the privacy challenges. The configuration database may contain customer data used for testing purposes, but this can be avoided, e.g. by testing on synthetic data in a User Acceptance Testing environment. The contents of this configuration is stored with AES256 encryption, where the symmetric key is provided to the application as an environment variable/secret.

Permissions

Within the Convier application, each user is assigned two different roles: One for the application as a whole, and one for each project. The roles are determined by the authentication provider, for example Azure AD.

Instance-level roles:

One users to instance-level role MANAGE can add external data sources (limited by firewall settings) and also track high-level application usage. By default, only MANAGE role can create new projects.

The AUDIT instance role can query the internal audit log database, if enabled

Project-level roles

The READ role is only able to access data, and make individual configuration changes that can not be shared with others without approval. They can not add external data source connections. The MANAGE project role is able to share configuration changes with others, and is usually reserved for Convier personel and customer subject matter experts. The OWN project role can do the same as the MANAGE project role, but can also assign project roles to others.

File: Installation wizard with secret store

Installation wizard with secret store (from 0.2511.1)

By default, Convier reads config like OIDC client ID and secret from environment variables, but configuration may also be fetched from a secrets store if running in a supported environment (e.g. App Service).

Setup

Azure Key Vault

To fetch config directly from a key vault in Azure when running as an App Service, do the following:

Google Secrets Manager

Install

File: Data Health Checks

Data Health Checks

Rules can be established to monitor that conected data sources are correct and up to date. Typical checks include the presence of transactions or KYC answers that are less than N days old, and exist to make sure ingestion jobs are running.

Data health checks are configured in edit mode from the Browse application in Convier, and results are available through the API and on the project home page. In simple configuration, the check is healthy if at least one object is found using the configured filters (e.g. at least one transaction from the last 24 hours).

The health checks on a source are shared between users authorized to connect to the source, and are by default refreshed every five minutes.

Define data filters

image

Configure health check

image

View health check

image

File: Dynamics CRM API

Dynamics CRM API

How to get to the “Manage sources” page


Convier supports Odata APIs like the Dyanmics CRM API. This enables Convier to both read from and write data to the Dynamics platform (or other CRM that has an API).

About access to Dynamics CRM

By default, the Dynamics CRM API supports giving delegated access to applications using the “user_impersonation” scope. Giving this access to the Convier app registration (or other applications) lets the application access Dynamics on behalf of the user, inheriting the user’s permissions. As this would enable Convier to access whatever the user can access in Dynamics, this is for security reasons not desired. In our experience, it is only relevant for Convier to access one or a few “entity sets”, for example a list of Enhanced Due Diligence tasks.

The following is a guide to give the Convier app registration “application” access to an individual entity set in Dynamics. This will enable the Convier app to work with the entity tasks without relying on user permissions, which also prevents Convier from being able access other parts of Dynamics.

Please note that giving application access only should be given in combination with requiring assignment to the Coniver app registration. Without it, it could become possible for authenticated users who are not themselves authorized to access the entity set to access it through Convier.

Contact Convier Support if you are having problems connecting Convier to your Dynamics CRM installation.

Application access to individual Entity Sets in Dynamics CRM

File: Technical documentation

Convier Technical documentation

This category gives an overview over installation and configuration of the Convier platform, as well as a description of the technical architecture.

File: Data sources

Data sources

Common to connecting to all data sources, is to first switch to edit mode, and then going to the “Manage sources” page of the project. Supported data sources that are not yet described here include Spreadsheets from OneDrive, CSV-sources (data stored in config) and Neo4j.

Edit mode

Manage sources

File: Information Security

Information Security

Convier Information Security Officer: Petter Chr. Bjelland (CTO): petter.bjelland@convier.com

Access

There are multiple levels of authentication and authorization in Convier:

Access to Convier

The first level is firewall/network configuration. As Convier is installed within your infrastrcture, only clients within the internal network should be able to reach the server. The second level of security is user authentication and authorization with OIDC/OAuth. A client (App Registration in Azure) is created, which Convier uses for access control. Users and groups are granted access to this client. Users without access cannot reach the application or any projects. A user has to be assigned role Task.Read and/or Task.Manage in the App Registration to be able to access Convier. By default, only users with the Manage role can create projects in Convier.

Instance managers have the option to invalidate all authenticated sessions, forcing re-authentication and authorization. This may be relevant after an incident, for example after misconfiguration of access.

Authentication and Authorization (as of 0.2508.4)

Convier uses OIDC to authenticate and authorize users. An authenticated user will be assigned one cookie stored in its browser:

The cookie is stored with flags Secure, HttpOnly and SameSite=Lax.

Access to projects

Within a project, users have the role of Read, Manage, or Own. Users with the Own role control who has access to the project.

Projects can be shared with app roles (most commonly Task.Read) and individual users, including those who have not logged in yet (though they still need to pass the first level to gain access). Users are assigned a role in the project.

It’s also possible to create new App Roles in the OIDC client and grant access to projects based on these. Users must then be assigned the App Role, for example through the Application Registration page in the Azure Portal, to gain access.

Difference between Read and Manage in a project:

It is possible to share projects with users who haven’t logged in yet, but not with users who don’t have access to the application. Access to the application is controlled through your existing AD and access control/SSO.

Access to data sources

Similar to projects, individual data sources within a project, like databases or APIs, may be associated with a role. If a required role is specificed, users without the role will be prevented from seeing, connecting to, or retrieving data from the source. In addition to preventing access to the source, Convier makes a best effort to remove any metadata about the source from the configuration available to the user. Metadata that is removed includes the names of the fields loaded from the source, how it is presented, and how it is reported on.

Note: The data model configured from a restricted data source will be visible to all users who have access to the project. The data model contains type name (like “Customer”), icon and fields (like “Name”). This information is not removed as it would break configuration functionality. If the data model itself is considered too sensitive to be visible, a separate project should be created for the data source.

Encryption

In transit

Convier supports encrypted communication with both client and data sources. How TLS is implemented on client-server communication depends on the installation pattern that is used. Convier can boot with a PKCS12 export (e.g. Let’s Encrypt) directly, or behind a proxy that handles encryption, e.g. Azure App Service.

At rest

Convier stores project configuration, including data source credentials, in a database. Credentials are never sent to the frontend application. This database can be configured to be stored in an external database server, but by default it is stored in a SQLite database persisted locally next to the service. The contents of the configuration is by default encrypted with AES256, but a different encryption method may be configured. The symmetric AES256 key is provided to the service as an environment variable, either in the .env file next to docker-compose.yml, or through the configuration of the Azure App Service.

Symmetrically encrypted configuration data

Rotate symmetric encryption key

The encryption key in environment variable CONFIG_B64_ENCRYPTION_KEYcan be changed by following the following steps:

  1. Ensure you have a fresh backup of internal database (JDBC_CONNECTION_STRING)
  2. Generate a new base64-encoded, 256 bit encryption key, e.g. using openssl rand -base64 32 Make a copy of this key
  3. Assign the new key to environment variable CONFIG_B64_ENCRYPTION_KEY_ROLLING
  4. Restart the Convier instance
  5. Refresh instance front page (project list), click button Roll encryption key that has appeared
  6. Wait for confirmation that procedure was successful
  7. Assign newly generated key to environment variable CONFIG_B64_ENCRYPTION_KEY
  8. Unset CONFIG_B64_ENCRYPTION_KEY_ROLLING (normal changes will be blocked while set)
  9. Restart the Convier instance
  10. Verify that project(s) opens with configuration
  11. Done

Secrets

Other sensitive information Convier needs to operate includes the secret for the OIDC client used for authentication. This secret, as well as other OIDC configuration is provided to the service as environment variables, either in the .env file next to docker-compose.yml, or through the configuration of the Azure App Service.

Software Development Life Cycle

Our Software Development Life Cycle (SDLC) is designed to provide both high development speed and secure deployments. It also enables customers to anticipate and test future releases by setting up development. We actively use internal and external static code analysis, dependency analysis, unit and integration tests to ensure the security and correctness of our software. All changes that are shipped to customers are first reviewed by at least two Convier employees.

Issue handling

When issues (security or functional) in the software are identified, they are assigned a priority between P0 and P3:

Tooling

Frontend

Backend

CI/CD

Vulnerability management

We use Github dependabot for automatic vulnerability detection and dependency updates. Each identified vulnerability in a 3rd party library is assessed, and patches for high severity vulnerabilities are merged and released without unnecessary delay. In the case of a critical vulnerability, Convier will reach out to relevant customer resources.

Security testing

Independent, third-party penetration testing of the Convier application is performed on a regular basis, and in relation to larger changes that may affect application security. The last third-party penetration test was performed October 2024 and identified issues have been resolved. The test report is available upon request.

Additional instrumentation of the service

If you want to attach a security agent (e.g. from Contrast Security) or similar to the service, you can do so by setting the environment variable JAVA_OPTS=-javaagent:/path/to/agent.jar.

File: Checklist Installation

Checklist Installation

The purpose of this document is to list common steps needed to install a Convier instance up until the creation of a project.

File: Logging and Auditing Updated for version: 0.2601.1

Logging and Auditing

Convier produces two different types of logs: Service logs and Audit logs.

Service logs

The service logs contains a mix of access log and other internal service related log entries. It is produced using log4j. An excerpt from an access log:

2024-12-18T07:29:11: [INFO]  INFO - 123.123.123.123 - user@acme.com [18/Dec/2024:07:29:11 +0000] "PUT /convier/api/read/aml_platform_develop/main/count HTTP/1.1" 200 53 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0)"
2024-12-18T07:29:11: [INFO]  INFO - Post-filtering 157 found links
2024-12-18T07:29:11: [INFO]  INFO - 123.123.123.123 - user@acme.com [18/Dec/2024:07:29:11 +0000] "POST /convier/api/async-read/aml_platform_develop/main/request HTTP/1.1" 200 18406 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0)"

The access log format may be modified using the LOG_FORMAT environment setting. See the Undertow documentation for more information.

Audit logs

The audit log is written to Azure Log Service or a SQL database of your choice, but must be enabled. To remove the possibility of removing traces of misuse, it is recommended that users of Convier do not have access to this database themselves.

Write to SQL database

Use the configuration settings:

Tables and fields in the audit logging database is automatically created.

Write to Azure Log Service

With Data Collection Rule (From 0.2601.1)

Shared key (From 0.2507.1)

Audit log contents

An audit log entry contains the following fields:

We currently do not include raw response playloads in the audit log, as they may be quite large. Audit log entries are immediately written to the database, there are not written in batches.

These are the topics being logged

An example log entry on the search topic:

field value
project_id aml
branch main
timestamp 2024-12-10T10:00:00Z
user_id user@acme.com
topic search
payload {"query":"test","fields":["CUSTOMER_NAME"],"sourceIds":["dwh"]}
response {"status": "OK"}

File: Config Orchestration

Config Orchestration

The project in a Convier instance can be configured by another Convier instance. A typical use case for this, is to have the User Acceptance Testing environment manage the Production environment, to make sure testing occurs in a relaistic environment. It also enables multiple banks to securely share the same Convier configuration. Below is a list of steps needed to set up Config Orchestration when running with Azure/Entra ID, followed by some information security considerations.

Security considerations

File: Report storage Updated for version: 0.2504.1

Report storage

Reports generated in Convier can be stored in a database (“internal”), or in an existing system, like Microsoft Dynamics (“external”). Storage and retriveal of externally stored reports are configured using data sources, analytics and actions.

Azure Storage Account

Reports may be stored in Azure Storage Account containers. You may store reports in different containers for different reports actions, for example a mutable container store for latest working copy of a report, and a immutable (“write-only-read-many”) container for archived/completed reports. It requires that either Managed Identity is available, or that Convier is running with an App Registration from Entra ID.

Environment variables:

Google Storage Bucket (>= 0.2511.1)

Environment variables:

Internal report storage

Internal storage is enabled by setting the following environment variables:

To verify that internal report storage is enabled, check the service log for the following message INFO - Internal report storage: enabled.

If enabled, the required table and columns needed are automatically created. A row is added to the table each time a user clicks “Save” on the report, so there can be multiple versions of the same task/case/report. Each row consists of the following data:

column type example
project_id ID of proejct aml
inserted Epoch ms 1735813124631
user_id ID of user saving the report user@acme.com
object_id ID of task/case/report EDD-1234-001
content Report JSON [{"sectionId": "Intro", "content": {...}}, ...]
loaded_data Report data JSON (if enabled) {"timestamp": ..., "object": {...}, "connected": {...}}
loaded_data_simplified Properties and data model {"object_types": ..., "field_types": {...}, "data": {...}}
section_texts Report section texts {"Intro": "Lorem ipsum...", ...}
action Save/Close/Approve/etc. Save

In-browser report storage

While a user is editing a report, a copy of the contents is stored within the user’s browser (using IndexedDB). This is to prevent loss of data in case of system, network or power outage, or in the case of events like accidental page refresh.

File: Running as App Service in Azure

Running as an App Service in Azure

Summary

Convier can run within an Single Docker Container App Service in Azure. The Docker image is downloaded from Convier’s private repository, hosted on Azure. It can be assigned to its own subscription and resource group. By default the application writes config to a persistent storage attached to the app service, which by default is backed up every hour. The application can automatically upgrade when new versions of the Docker image becomes available.

Preparation

Register enterprise application

Register a single tenant enterprise application, e.g. named Convier Single Tenant from the Azure portal. Single tenant means the enterprise applications only can be used within your organization.

Under app registrations, API permissions, add permission User.Read this allows the app to fetch basic information about logged in users.

Under app registrations, App roles, add three roles:

Groups can be assigned to the different roles. The only difference between Task.Read and Task.Manage is the ability to make changes for other users. Task.Audit is allowed to query the audit log.

If you want to restrict access to Convier to certain users/groups, see the documentation in Azure for how to restrict access to the application.

Create a client secret that will be used by the Convier app to authorize users.

Create a new subscription

Optionally create a new subscription for the App Service.

Set up App Service

The following are two different methods to set up Convier as an App Service on Azure. The first option is the preferred and simplest method.

Please note that with local (default) configuration, Convier does not support redundancy, make sure instance count is 1, or configure a central database connection (JDBC_CONNECTION_STRING).

Option 1 - With an ARM template:

Open Azure Portal, click “Create a resource”, search for “Template deployment” and select “Template deployment (deploy using custom templates)”.

image

Click “Create”, then “Build your own template in the editor”. Paste in the following in the editor:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "docker_username": {                  
      "type": "string"
    },
    "docker_password": {          
      "type": "securestring"
    }, 
    "oidc_client_id": {
      "type": "string"
    },
    "oidc_client_secret": {
      "type": "securestring"
    },
    "encryption_key": {
      "type": "securestring"
    }
  },
  "variables": {
      "unique_suffix": "[tolower(uniqueString(resourceGroup().Id))]",
      "app_name": "[concat('convier-', variables('unique_suffix'))]",
      "app_plan_name": "[concat('convier-app-plan-', variables('unique_suffix'))]",
      "instance_url": "[concat('https://', variables('app_name'), '.azurewebsites.net/convier')]",
      "oidc_config_endpoint": "[concat('https://login.microsoftonline.com/', subscription().tenantId, '/v2.0/.well-known/openid-configuration')]"        
  },
  "resources": [
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2018-02-01",
      "name": "[variables('app_plan_name')]",
      "location": "[resourceGroup().location]",
      "sku": {
        "name": "B1",
        "tier": "Basic"
      },
      "kind": "linux",
      "properties": {
        "reserved": true
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2016-08-01",
      "name": "[variables('app_name')]",
      "location": "[resourceGroup().location]",
      "tags": {},
      "kind": "app,linux,container",
      "dependsOn": [
        "[variables('app_plan_name')]"
      ],
      "properties": {
        "enabled": true,
        "hostNameSslStates": [
          {
            "name": "[variables('instance_url')]",
            "sslState": "Disabled",
            "hostType": "Standard"
          }
        ],
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('app_plan_name'))]",
        "siteConfig": {
          "linuxFxVersion": "DOCKER|convier.azurecr.io/convier:stable"                    
        },
        "httpsOnly": true,
        "publicNetworkAccess": "Disabled"
      }
    },
    {
      "type": "Microsoft.Web/sites/config",
      "apiVersion": "2018-11-01",
      "name": "[concat(variables('app_name'), '/appsettings')]",
      "properties": {
        "DOCKER_REGISTRY_SERVER_URL": "https://convier.azurecr.io",
        "DOCKER_REGISTRY_SERVER_USERNAME": "[parameters('docker_username')]",
        "DOCKER_REGISTRY_SERVER_PASSWORD": "[parameters('docker_password')]",
        "WEBSITES_ENABLE_APP_SERVICE_STORAGE": "true",
        "CONFIG_B64_ENCRYPTION_KEY": "[parameters('encryption_key')]",
        "JDBC_CONNECTION_STRING": "jdbc:sqlite:/home/convier.db",
        "OIDC_CLIENT_ID": "[parameters('oidc_client_id')]",
        "OIDC_CLIENT_SECRET": "[parameters('oidc_client_secret')]",
        "OIDC_CONFIGURATION_ENDPOINT": "[variables('oidc_config_endpoint')]",
        "OIDC_SCOPES": "[concat(parameters('oidc_client_id'), '/.default offline_access')]",
        "PUBLIC_URL": "[variables('instance_url')]",
        "OIDC_ROLE_MANAGE": "Task.Manage",
        "SERVER_PORT": "80"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Web/sites', variables('app_name'))]"
      ]
    }
  ]
}

Click “Save”. You should see something like the below:

image

Fill in the requested information. You should receive the docker username and password through a secure channel from Convier. The encryption key can be generated using openssl rand -base64 32. The Convier team can also assist in generating this key. Click “Review + Create”, and then “Create”. Once the deployment has completed, click “Go to resource group” to set up the network configuration for the App Service. By default no one is allowed access to the service.

Option 2 - Manual creation:

Create a resource group

Optionally create a new resource within the chosen subscription for the App Service.

Create an App Service Plan

Optionally create a new app service plan.

Create the App Service resource

Create a new Web App App Service and assigned it to the chosen subscription and resource group. Give the app an appropriate name and add the following configuration:

Basics

Docker

Networking

Review and create

Add networking restrictions

To add a layer of security, from the app service portal, add restrictions to which IP addresses can access the application.

Configuration

The Convier app accepts configuration in the form of environment variables. These configurations are enrypted and stored within Azure by Microsoft.

Under Configuration, click Advanced edit and add the following entries:

[
  {
    "name": "CONFIG_B64_ENCRYPTION_KEY",
    "value": "<encryption key, see below>",
    "slotSetting": false
  },
  {
    "name": "DOCKER_ENABLE_CI",
    "value": "true",
    "slotSetting": false
  },  
  {
    "name": "DOCKER_REGISTRY_SERVER_URL",
    "value": "https://convier.azurecr.io",
    "slotSetting": false
  },
  {
    "name": "DOCKER_REGISTRY_SERVER_USERNAME",
    "value": "<docker username>",
    "slotSetting": false
  },
  {
    "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
    "value": "<docker password>",
    "slotSetting": false
  },
  {
    "name": "JDBC_CONNECTION_STRING",
    "value": "jdbc:sqlite:/home/convier.db",
    "slotSetting": false
  },
  {
    "name": "INTERNAL_AUDIT_LOG_JDBC_CONNECTION_STRING",
    "value": "jdbc:sqlite:/home/audit.db",
    "slotSetting": false
  },
  {
    "name": "OIDC_CLIENT_ID",
    "value": "<client id>",
    "slotSetting": false
  },
  {
    "name": "OIDC_CLIENT_SECRET",
    "value": "<client secret>",
    "slotSetting": false
  },
  {
    "name": "OIDC_CONFIGURATION_ENDPOINT",
    "value": "https://login.microsoftonline.com/<tenant id>/v2.0/.well-known/openid-configuration",
    "slotSetting": false
  },
  {
    "name": "OIDC_ROLE_MANAGE",
    "value": "Task.Manage",
    "slotSetting": false
  },
  {
    "name": "OIDC_SCOPES",
    "value": "openid profile offline_access",
    "slotSetting": false
  },
  {
    "name": "PUBLIC_URL",
    "value": "public_url",
    "slotSetting": false
  },  
  {
    "name": "SERVER_PORT",
    "value": "80",
    "slotSetting": false
  },    
  {
    "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
    "value": "true",
    "slotSetting": true
  }
]

Scope offline_access enables users to stay logged in.

A key CONFIG_B64_ENCRYPTION_KEY to enable encryption of configuration. The value of CONFIG_B64_ENCRYPTION_KEY must be a 32 character random string (e.g generated with openssl rand -base64 32). It is an AES encryption key used for symmetric encryption of configuration in the internal database. The internal database is by default a SQLite database stored in the persistent storage.

JDBC_CONNECTION_STRING the full connection string to the database that will contain configuration.

INTERNAL_AUDIT_LOG_JDBC_CONNECTION_STRING the full connection string to the database that will store audit logs.

Next steps

File: Salesforce API

Salesforce API

How to get to the “Manage sources” page


High-level flow

In Entra

In Salesforce

global class ConvierTokenExchangeHandler extends Auth.Oauth2TokenExchangeHandler {

    private static final String OIDC_AUDIENCE = '$entraSalesforceAppId';
    private static final String EXTERNAL_IDP_JWKS_URL = 'https://login.microsoftonline.com/$tenantId/discovery/v2.0/keys';

    private Auth.UserData getUserDataFromJWT(Auth.JWT jwt) {        
        String email = (String) jwt.getAdditionalClaims().get('upn');

        Auth.UserData userData = new Auth.UserData(null, null, null, null, email, null, null, null, null, null, null);

        return userData;
    }

    private User findExistingUser(Auth.UserData data) {
        String email = data.email;

        List<User> existingUser = [SELECT Id, Username, Email, FirstName, LastName, Alias, ProfileId FROM User WHERE Email=:email LIMIT 1];

        if (existingUser.isEmpty()) {
            return null;
        }

        return existingUser[0];
    }

    // Manual extraction of audience, as built-in method does not seem to exist
    private string getAudience(String incomingToken) {
        List<String> parts = incomingToken.split('\\.');
        
        Integer pad = Math.mod(4 - Math.mod(parts[1].length(), 4), 4);
        String padding = '='.repeat(pad);
        
        String payloadB64 = parts[1].replace('-', '+').replace('_', '/') + padding;
        String payloadJson = EncodingUtil.base64Decode(payloadB64).toString();
        Map<String, Object> claims = (Map<String, Object>) JSON.deserializeUntyped(payloadJson);
        Object audClaim = claims.get('aud');
        if (audClaim instanceof String) {
            return (String) audClaim;
        } else if (audClaim instanceof List<Object>) {
            return (String)((List<Object>)audClaim)[0];
        }
        return null;
    }

    global override Auth.TokenValidationResult validateIncomingToken(String appDeveloperName, Auth.IntegratingAppType appType, String incomingToken, Auth.OAuth2TokenExchangeType tokenType) {        
        Auth.JWT jwt = Auth.JWTUtil.validateJWTWithKeysEndpoint(incomingToken, EXTERNAL_IDP_JWKS_URL, true);
        
        String audience = getAudience(incomingToken);

        if (!audience.equals(OIDC_AUDIENCE)) {
            return new Auth.TokenValidationResult(false);
        }
    
        Datetime expClaim = (Datetime) jwt.getAdditionalClaims().get('exp');
          if (expClaim < Datetime.now()) {
              return new Auth.TokenValidationResult(false);
          }

        Auth.UserData userData = getUserDataFromJWT(jwt);
        if (userData == null) {
            return new Auth.TokenValidationResult(false);
        }

        return new Auth.TokenValidationResult(true, null, userData, incomingToken, tokenType, null);        
    }

    global override Boolean mapToUser(Id networkId, Auth.TokenValidationResult result, Boolean canCreateUser, Boolean canCreateContact, String appDeveloperName, Auth.IntegratingAppType appType) {
        return true;
    }

    global override User getUserForTokenSubject(Id networkId, Auth.TokenValidationResult result, Boolean canCreateUser, String appDeveloperName, Auth.IntegratingAppType appType) {
        Auth.UserData data = result.getUserData();

        return findExistingUser(data);
    }
}

In Convier

Setup with mactine-to-machine (client_credentials) authentication

In Salesforce

In Convier

File: Snowflake

Snowflake

How to get to the “Manage sources” page


See the Snowflake documentation for more details on security integrations in Snowflake.

This page assumes you are using Entra ID / Azure AD, and that the OIDC client for Convier is already set up. We also assume the use role session:CONVIER_SNOWFLAKE_USER. Adjust role according to your setup.

Refefences:

You find Object ID under “Entprise Applications” in the Azure Portal, next to “Application ID”

Create Application Registration in Azure that will be added to a Snowflake security integration

References:

Add security integration in Snowflake

If you connect to Snowflake using a security integration, you can choose between delegated and application access. In delegated mode, the Convier will authenticate on behalf of users, meaning that users in Convier also must exist in Snowflake. In application mode, the Convier application is given access directly to Snowflake, and any user who has access to the created project and source in Convier, will have access to Snowflake. The decision between these two will affect where audit logging should occur.

Oauth2 On-Behalf-Of user access

Use this security integration if you want to authenticate individual users in Snowflake.

In Azure, add “scope” session:CONVIER_SNOWFLAKE_USER to $snowflakeAppId.

In Snowflake:

CREATE OR REPLACE SECURITY INTEGRATION external_oauth_azure_1
  TYPE = external_oauth
  ENABLED = true
  EXTERNAL_OAUTH_TYPE = azure
  EXTERNAL_OAUTH_ISSUER = 'https://sts.windows.net/$tenantId/'
  EXTERNAL_OAUTH_JWS_KEYS_URL = 'https://login.microsoftonline.com/$tenantId/discovery/v2.0/keys'
  EXTERNAL_OAUTH_AUDIENCE_LIST = ('api://$snowflakeAppId')
  EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'upn'
  EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'login_name'

This assumes users are automatically synced with Entra ID (e.g. using SCIM), and that the user has role CONVIER_SNOWFLAKE_USER in Snowflake.

Oauth2 application access

Use this if you want to give the OIDC client itself access to Snowflake.

In Azure, add “app role” session:CONVIER_SNOWFLAKE_USER to $snowflakeAppId

In Snowflake, create system user:

CREATE USER CONVIER_APP 
  LOGIN_NAME = '$convierObjectId'
  DISPLAY_NAME = 'Convier';

Then create security integration:

CREATE OR REPLACE SECURITY INTEGRATION external_oauth_azure_1
  TYPE = external_oauth
  ENABLED = true
  EXTERNAL_OAUTH_TYPE = azure
  EXTERNAL_OAUTH_ISSUER = 'https://sts.windows.net/$tenantId/'
  EXTERNAL_OAUTH_JWS_KEYS_URL = 'https://login.microsoftonline.com/$tenantId/discovery/v2.0/keys'
  EXTERNAL_OAUTH_AUDIENCE_LIST = ('api://$snowflakeAppId')
  EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'sub'
  EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'login_name'

You’ll need to include EXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE' to the query above if you use the default session:role-any.

Using a system user and password

It is also possible to connect to Snowflake using basic credentials. In these cases, create a user with password in Snowflake, then select “Basic credentials” under authentication below.

Configure connection

In Convier:

Misc

File: SQL Sources

SQL sources

By default, Convier can connect to SQL server / Aure SQL, Postgres, SQLite and Snowflake databases. Connections to databases are established using JDBC. Table of contents below for more details.

File: SQL Server / Azure SQL

SQL Server / Azure SQL

<- How to get to the “Manage sources” page


JDBC config

Managed Identity (App Service):

Token based:

Basic credentials

Save

Connect and save config ->

File: Support

Support contact

File: Telemetry

Telemetry

Enabling telemetry data is optional, but is helpful for Convier to know which versions of the software is running, which migrations have run, and some metadata about use and resources. Telemetry data helps the software development process. The telemetry data is sent once when the systems starts and contains the following information:

Telemetry is enabled by setting the environment variables TELEMETRY_APP_ID to something descriptive, e.g. “acme_prod”.

The telemetry data is be sent to https://telemetry.convier.com. Some changes in firewall settings may be needed.