Overview

Prima server configuration is managed through the appsettings.json file located in the Prima installation directory (typically C:\Program Files\FortelineaSoftwareSystems\Prima\Services\PrimaWebService).

Configuration File Structure

The configuration uses the standard ASP.NET Core configuration system. Settings can be overridden using:

  • appsettings.json - Base configuration
  • Environment variables
  • Command-line arguments

Configuration Sections

Use the tabs on the left to learn about configuring each section:

  • Authentication - Windows/LDAP authentication, JWT settings, Identity configuration
  • Image Storage - Local file storage, S3-compatible cloud storage, path configuration
  • Web Server (Kestrel) - URLs, ports, HTTPS/SSL certificates, request limits
  • Database Connection - SQL Server connection strings, Entity Framework settings
Tip: After making configuration changes, restart the Prima Windows service for changes to take effect.

Authentication

Prima supports three authentication methods. The authentication method is determined automatically based on which configuration sections are present and fully configured.

Supported Authentication Methods

Method Use Case Configuration Section
Prima Built-in database authentication (default) No additional configuration required
LDAP Active Directory / LDAP integration LdapConfiguration
Okta Cloud-based identity management OktaConfiguration

Authentication Priority

When multiple authentication methods are configured, Prima uses this priority order:

  1. Okta - If OktaConfiguration is fully configured
  2. LDAP - If LdapConfiguration has AuthenticationType: "Ldap" and is fully configured
  3. Prima - Default fallback (built-in database authentication)

JWT Token Configuration

JWT tokens are used for API authentication regardless of which authentication method is active.

{
  "JwtTokenSettings": {
    "Secret": "your-secret-key-here-minimum-32-characters",
    "RefreshTokenTTL": 2
  }
}
Property Type Description
Secret string Secret key for JWT token signing. Must be changed from default before production use.
RefreshTokenTTL integer Refresh token time-to-live in days (default: 2)
Security: The Secret value must be changed from "REPLACEME" before deploying to production. Use a strong, random string of at least 32 characters.

LDAP / Active Directory Configuration

Configure LDAP authentication to integrate with your organization's Active Directory.

{
  "LdapConfiguration": {
    "AuthenticationType": "Ldap",
    "Host": "ad.company.com",
    "Port": 636,
    "Domain": "company.com",
    "UserStore": "OU=Employees,DC=company,DC=com",
    "Protocol": "LDAPS",
    "AuthType": "Negotiate",
    "Version": 3,
    "TimeOut": "00:01:00",
    "LdapRetryInterval": 1500
  }
}
Required Properties
Property Type Description
AuthenticationType string Must be set to "Ldap" to enable LDAP authentication
Host string LDAP server hostname or IP address (e.g., "ad.company.com")
Protocol string "LDAP" (port 389, unencrypted) or "LDAPS" (port 636, encrypted)
Optional Properties
Property Type Default Description
Port integer 636 or 389 LDAP server port (auto-selected based on Protocol)
Domain string Auto-detected Active Directory domain name (e.g., "company.com")
UserStore string - Distinguished name for user search (e.g., "OU=Users,DC=company,DC=com")
Version integer 3 LDAP protocol version
AuthType string "Negotiate" Authentication method: "Basic", "Negotiate", or "Digest"
TimeOut timespan "01:00:00" LDAP connection timeout
LdapRetryInterval integer 1500 Retry interval in milliseconds
CertificateVerificationMethod string "Default" SSL cert verification: "Default", "Skip", or "CustomFile"
X509CertificatePath string - Path to X.509 certificate (when using "CustomFile")
Auto-Discovery: When Host is not specified, Prima attempts to auto-discover the domain controller using Domain.GetComputerDomain().

Okta Configuration

Configure Okta for cloud-based identity management using OAuth 2.0.

{
  "OktaConfiguration": {
    "Domain": "mycompany.okta.com",
    "ClientId": "0oab1234567890ABC",
    "ClientSecret": "X7aB_cD-eFg_HiJk_lMnOpQrStUvWxYz123456789",
    "AuthorizationServerId": "default",
    "TokenValidationCacheDuration": "00:05:00",
    "ValidateAudience": true,
    "ValidateIssuer": true
  }
}
Required Properties
Property Type Description
Domain string Your Okta tenant domain (e.g., "company.okta.com")
ClientId string OAuth 2.0 application client ID from Okta
ClientSecret string OAuth 2.0 application client secret from Okta
Optional Properties
Property Type Default Description
AuthorizationServerId string "default" Okta authorization server ID
TokenValidationCacheDuration timespan "00:05:00" Duration to cache token validation results
ValidateAudience boolean true Whether to validate the audience claim in tokens
ValidateIssuer boolean true Whether to validate the issuer claim in tokens
Okta Setup Steps
  1. Create an Okta application with OAuth 2.0 (Web Application type)
  2. Configure the authorization server (typically use "default")
  3. Enable the Resource Owner Password grant type
  4. Copy the Client ID and Client Secret from the application settings
  5. Configure these values in appsettings.json
Issuer URL: Prima constructs the issuer URL as: https://{Domain}/oauth2/{AuthorizationServerId}
Example: https://company.okta.com/oauth2/default

Configure session cookies for web UI authentication.

{
  "CookieAuthentication": {
    "ExpireTimeSpan": "01:30:00",
    "SlidingExpiration": true
  },
  "CookiePolicyOptions": {
    "Secure": "Always",
    "HttpOnly": "Always",
    "MinimumSameSitePolicy": "Lax"
  }
}
Property Type Default Description
ExpireTimeSpan timespan "01:30:00" Session timeout duration
SlidingExpiration boolean true Extend expiration on each request
Secure string "Always" Cookie transmission: "Always", "None", "SameAsRequest"
HttpOnly string "Always" Prevent JavaScript access: "Always" or "None"
MinimumSameSitePolicy string "Lax" CSRF protection: "None", "Lax", "Strict"
Load Balancer Note: When running behind a load balancer that terminates HTTPS, set "Secure": "None" to allow cookies over the internal HTTP connection.

Configuration Examples

Example 1: LDAP with Active Directory
{
  "LdapConfiguration": {
    "AuthenticationType": "Ldap",
    "Host": "ad.company.com",
    "Port": 636,
    "Domain": "company.com",
    "UserStore": "OU=Employees,DC=company,DC=com",
    "Protocol": "LDAPS",
    "AuthType": "Negotiate",
    "Version": 3,
    "TimeOut": "00:01:00"
  },
  "JwtTokenSettings": {
    "Secret": "your-production-secret-key-at-least-32-chars",
    "RefreshTokenTTL": 2
  }
}
Example 2: Okta Cloud Authentication
{
  "OktaConfiguration": {
    "Domain": "mycompany.okta.com",
    "ClientId": "0oab1234567890ABC",
    "ClientSecret": "X7aB_cD-eFg_HiJk_lMnOpQrStUvWxYz123456789",
    "AuthorizationServerId": "default"
  },
  "JwtTokenSettings": {
    "Secret": "your-production-secret-key-at-least-32-chars",
    "RefreshTokenTTL": 2
  }
}
Example 3: Prima Default (Built-in Database)
{
  "LdapConfiguration": {
    "AuthenticationType": "Prima"
  },
  "JwtTokenSettings": {
    "Secret": "your-production-secret-key-at-least-32-chars",
    "RefreshTokenTTL": 2
  }
}
Tip: After making authentication configuration changes, restart the Prima Windows service for changes to take effect.

Image Storage

Configure where Prima stores digital images including cassette images, slide images, specimen photos, and scanned documents. Prima supports four storage modes: File (local/network paths), S3 (Amazon S3 or compatible services), Azure Blob (Microsoft Azure Blob Storage), and Advanced (different storage per image type).

Storage Modes Overview

Only one storage mode can be active at a time. Configure one of the following in appsettings.json:

Mode Use Case Configuration Key
File Local disk or network share storage (simplest option) ImageStorage.File
S3 Cloud storage using Amazon S3 or compatible services (Digital Ocean Spaces, MinIO) ImageStorage.S3
Azure Blob Cloud storage using Microsoft Azure Blob Storage ImageStorage.AzureBlob
Advanced Different storage location per image type (e.g., slides in S3, documents on network share) ImageStorage.Advanced

File Storage Mode

The simplest configuration stores all images in subdirectories under a single root path.

{
  "ImageStorage": {
    "File": {
      "RootDirectory": "C:\\ProgramData\\Prima\\Storage"
    }
  }
}

Prima automatically creates subdirectories for each image type:

  • CassetteImages/ - Photos of cassettes
  • SlideImages/ - Whole slide images
  • SpecimenImages/ - Specimen gross photos
  • Documents/ - Scanned documents and attachments
Network Shares: You can use a UNC path for network storage: \\\\server\\share\\PrimaStorage (note the escaped backslashes in JSON).

S3 Storage Mode

Store all images in an Amazon S3 bucket or S3-compatible service (Digital Ocean Spaces, MinIO, etc.).

Step 1: Define Credential Profiles

First, create one or more credential profiles that can be referenced by storage configurations:

{
  "StorageCredentialProfiles": [
    {
      "Name": "aws-production",
      "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
      "SecretAccessKey": "${secrets:env:AWS_SECRET_KEY}",
      "Region": "us-east-1",
      "Endpoint": null
    },
    {
      "Name": "digitalocean-spaces",
      "AccessKeyId": "DO00EXAMPLE123",
      "SecretAccessKey": "${secrets:env:DO_SPACES_SECRET}",
      "Region": "nyc3",
      "Endpoint": "https://nyc3.digitaloceanspaces.com"
    }
  ]
}
Property Description
Name Unique identifier for referencing this profile
AccessKeyId AWS access key ID or equivalent for S3-compatible services
SecretAccessKey Secret key (supports secret resolution syntax - see below)
Region AWS region (e.g., us-east-1) or service region
Endpoint Custom endpoint URL for S3-compatible services (leave null for AWS)
Step 2: Configure S3 Storage
{
  "ImageStorage": {
    "S3": {
      "CredentialProfile": "aws-production",
      "BucketName": "prima-images",
      "Prefix": "prod/"
    }
  }
}
Property Description
CredentialProfile Name of a credential profile defined in StorageCredentialProfiles
BucketName S3 bucket name
Prefix Optional prefix for all object keys (useful for multi-tenant or environment separation)
S3 Settings (Optional)

Configure retry behavior and timeouts for S3 and Azure Blob operations:

{
  "S3Settings": {
    "TimeoutSeconds": 30,
    "MaxRetryAttempts": 3,
    "RetryDelayMilliseconds": 500
  }
}

Azure Blob Storage Mode

Store all images in a Microsoft Azure Blob Storage container.

{
  "ImageStorage": {
    "AzureBlob": {
      "ConnectionString": "${secrets:env:AZURE_STORAGE_CONNECTION_STRING}",
      "ContainerName": "prima-images",
      "Prefix": "prod/"
    }
  }
}
Property Description
ConnectionString Azure Storage account connection string (supports secret resolution syntax)
ContainerName Azure Blob container name
Prefix Optional prefix for all blob names (useful for multi-tenant or environment separation)
Connection String Format: You can find your connection string in the Azure Portal under Storage Account → Access Keys. The format is: DefaultEndpointsProtocol=https;AccountName=yourAccount;AccountKey=yourKey;EndpointSuffix=core.windows.net

Advanced Storage Mode

Configure different storage locations for each image type. This is useful for hybrid scenarios, such as keeping high-volume slide images in cloud storage while keeping documents on a local network share.

{
  "ImageStorage": {
    "Advanced": {
      "CassetteImage": {
        "Type": "File",
        "Path": "C:\\Storage\\Cassettes"
      },
      "SlideImage": {
        "Type": "S3",
        "CredentialProfile": "aws-production",
        "BucketName": "prima-slides",
        "Prefix": ""
      },
      "SpecimenImage": {
        "Type": "AzureBlob",
        "ConnectionString": "${secrets:env:AZURE_STORAGE_CONNECTION_STRING}",
        "ContainerName": "prima-specimens",
        "Prefix": ""
      },
      "ScannedDocument": {
        "Type": "File",
        "Path": "\\\\server\\share\\Documents"
      }
    }
  }
}

Each image type can be configured as File, S3, or AzureBlob:

File Target
{ "Type": "File", "Path": "C:\\path\\to\\storage" }
S3 Target
{ "Type": "S3", "CredentialProfile": "name", "BucketName": "bucket", "Prefix": "optional/" }
Azure Blob Target
{ "Type": "AzureBlob", "ConnectionString": "...", "ContainerName": "container", "Prefix": "optional/" }

Secret Resolution

To avoid storing sensitive credentials in plain text, use secret resolution syntax for the SecretAccessKey field. Prima supports multiple secret providers:

Provider Syntax Example
Environment Variable ${secrets:env:VARIABLE_NAME} ${secrets:env:AWS_SECRET_KEY}
Azure Key Vault ${secrets:azure-keyvault:secret-name} ${secrets:azure-keyvault:prima-s3-secret}
AWS Secrets Manager ${secrets:aws-secrets:secret-name} ${secrets:aws-secrets:prima/storage/credentials}
Plain Text (no prefix) wJalrXUtnFEMI/K7MDENG/bPxRfi...
Configuring Secret Providers

If using Azure Key Vault or AWS Secrets Manager, configure the provider connection:

{
  "SecretProviders": {
    "AzureKeyVault": {
      "VaultUri": "https://my-vault.vault.azure.net/"
    },
    "AwsSecretsManager": {
      "Region": "us-east-1"
    }
  }
}
Security Best Practice: Never commit plain text credentials to source control. Use environment variables or a secrets manager for production deployments.

Complete Configuration Example

Here's a complete example using S3 storage with environment variable secrets:

{
  "StorageCredentialProfiles": [
    {
      "Name": "production-s3",
      "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
      "SecretAccessKey": "${secrets:env:PRIMA_S3_SECRET_KEY}",
      "Region": "us-east-1",
      "Endpoint": null
    }
  ],
  "ImageStorage": {
    "S3": {
      "CredentialProfile": "production-s3",
      "BucketName": "my-prima-images",
      "Prefix": "production/"
    }
  },
  "S3Settings": {
    "TimeoutSeconds": 30,
    "MaxRetryAttempts": 3,
    "RetryDelayMilliseconds": 500
  }
}

S3-Compatible Services

Prima works with any S3-compatible storage service. Set the Endpoint property to the service's S3 API URL:

Service Endpoint Example
Amazon S3 null (uses default AWS endpoints)
Digital Ocean Spaces https://nyc3.digitaloceanspaces.com
MinIO https://minio.example.com:9000
Backblaze B2 https://s3.us-west-000.backblazeb2.com
Tip: After making storage configuration changes, restart the Prima Windows service for changes to take effect.

Web Server (Kestrel)

Configure the ASP.NET Core Kestrel web server that hosts Prima's web interface and API.

Server Settings

Documentation in progress. This section will cover:
  • URL and port binding
  • HTTPS/SSL certificate configuration
  • Request size limits
  • Connection timeouts
  • HTTP/2 and HTTP/3 settings

Database Connection

Configure the connection to your SQL Server database.

Connection Settings

Documentation in progress. This section will cover:
  • Connection string format and options
  • Windows vs SQL authentication
  • Connection pooling settings
  • Command timeouts
  • Entity Framework configuration