# How to Configure mTLS Client Certificates for Enterprise HTTPS Servers in GeoLibre

> Secure enterprise HTTPS servers by configuring mTLS client certificates in GeoLibre. Set environment variables for automatic certificate presentation and mutual TLS authentication.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: how-to-guide
- Published: 2026-08-01

---

**Set three environment variables (`GEOLIBRE_HTTP_CA_CERT`, `GEOLIBRE_HTTP_CLIENT_CERT`, and `GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD`) before starting the GeoLibre desktop app, and the native HTTP client will automatically present the client certificate when enterprise servers request mutual TLS authentication.**

GeoLibre's desktop application uses a **native Rust HTTP client** to fetch tiles, OGC services, and remote rasters. When your organization requires **mutual TLS (mTLS)**—where the client must authenticate with a certificate—GeoLibre supports this through environment-based configuration without modifying source code. This guide explains how to configure mTLS client certificates for enterprise HTTPS servers based on the actual implementation in the GeoLibre codebase.

---

## Supported Certificate Formats and Variables

GeoLibre recognizes three environment variables controlling TLS behavior. These are processed once at startup in [`apps/geolibre-desktop/src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/src/lib.rs) and apply to all HTTPS requests made by the native client.

| Variable | Required | Purpose |
|----------|----------|---------|
| `GEOLIBRE_HTTP_CA_CERT` | No | Path to additional trusted CA certificates (PEM format). Appends to the OS trust store. |
| `GEOLIBRE_HTTP_CLIENT_CERT` | Yes for mTLS | Path to client certificate. Supports **PEM** (certificate chain + unencrypted PKCS-8 private key) or **PKCS#12** (`.p12` / `.pfx` bundle). |
| `GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD` | Conditional | Password for PKCS-12 files. Presence forces the PKCS-12 code path even without `.p12` extension. |

The constants are defined in [`lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/lib.rs) at lines 680-940:

```rust
const HTTP_CLIENT_CERT_ENV: &str = "GEOLIBRE_HTTP_CLIENT_CERT";
const HTTP_CLIENT_CERT_PASSWORD_ENV: &str = "GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD";

```

---

## How to Configure mTLS Client Certificates

### Step 1: Prepare Your Certificate Files

Obtain your enterprise client certificate from your security team. GeoLibre accepts two formats:

- **PEM format**: A single file containing the certificate chain followed by an unencrypted PKCS-8 private key. No password required.
- **PKCS#12 format**: A `.p12` or `.pfx` file containing both certificate and encrypted private key. Requires the `GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD` variable.

### Step 2: Set Environment Variables

Create a `.env` file in the GeoLibre desktop application folder or export variables in your shell session.

**Example: PKCS-12 with password**

```text
GEOLIBRE_HTTP_CA_CERT=/etc/ssl/certs/enterprise-root-ca.pem
GEOLIBRE_HTTP_CLIENT_CERT=/home/user/certs/client-identity.p12
GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD=EnterpriseSecret2024

```

**Example: PEM without password**

```text
GEOLIBRE_HTTP_CLIENT_CERT=/home/user/certs/client.pem

# No password variable → triggers PEM path via rustls

```

### Step 3: Restart GeoLibre

The native HTTP client is built as a **shared singleton** at application startup. Changes to environment variables require a restart to take effect.

---

## How the Native Client Loads Certificates

The certificate loading logic in [`lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/lib.rs) follows this decision tree:

1. **CA certificates**: If `GEOLIBRE_HTTP_CA_CERT` is set, the file is read as PEM and added to the rustls trust store using `add_root_certificate()`.

2. **Client identity**: If `GEOLIBRE_HTTP_CLIENT_CERT` is set:
   - **PKCS-12 path**: Triggered if file ends with `.p12`/`.pfx` **or** `GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD` is non-empty. Uses `Identity::from_pkcs12_der()` with the platform's native-tls backend (SChannel on Windows, Secure Transport on macOS, OpenSSL on Linux).
   - **PEM path**: Default fallback. Uses `Identity::from_pem()` via rustls.

This simplified Rust excerpt shows the core logic:

```rust
use std::env;
use reqwest::ClientBuilder;

fn build_http_client() -> reqwest::Result<reqwest::Client> {
    let mut builder = ClientBuilder::new();

    // Add enterprise CA if configured
    if let Ok(ca_path) = env::var("GEOLIBRE_HTTP_CA_CERT") {
        let ca_pem = std::fs::read(ca_path)?;
        builder = builder.add_root_certificate(
            reqwest::Certificate::from_pem(&ca_pem)?
        );
    }

    // Load client certificate for mTLS
    if let Ok(cert_path) = env::var("GEOLIBRE_HTTP_CLIENT_CERT") {
        let cert_data = std::fs::read(&cert_path)?;
        
        let is_pkcs12 = cert_path.ends_with(".p12") 
            || cert_path.ends_with(".pfx")
            || env::var("GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD").is_ok();
        
        if is_pkcs12 {
            let password = env::var("GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD")
                .unwrap_or_default();
            builder = builder.identity(
                reqwest::Identity::from_pkcs12_der(&cert_data, &password)?
            );
        } else {
            builder = builder.identity(
                reqwest::Identity::from_pem(&cert_data)?
            );
        }
    }

    builder.build()
}

```

Any certificate loading errors surface in the UI with messages like "Could not read client certificate …" sourced from [`lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/lib.rs) lines 680-940.

---

## When Does the Client Certificate Get Sent?

The configured certificate is **not transmitted to every server**. According to the architecture documentation at [`docs/architecture.md`](https://github.com/opengeos/GeoLibre/blob/main/docs/architecture.md) (lines 119-139), the native client behaves as follows:

- The singleton HTTP client stores the identity for the process lifetime.
- The underlying TLS library (rustls or native-tls) **only presents the certificate when the server sends a CertificateRequest** during the TLS handshake.
- If the server does not request client authentication, the certificate remains undisclosed.

This design ensures your client certificate is never leaked to arbitrary hosts. It is only exposed to endpoints that explicitly require mTLS.

---

## Using mTLS in JavaScript Fetch Calls

From the web-based UI, use standard `fetch()` calls. The request is proxied through the native client automatically:

```javascript
// Standard fetch—no special configuration needed
const response = await fetch('https://secure.enterprise.com/api/layers');
const tiles = await fetch('https://secure.enterprise.com/tiles/{z}/{x}/{y}.pbf');

```

The native client intercepts these requests and attaches the configured client certificate when the enterprise server demands it.

---

## Troubleshooting mTLS Configuration

| Symptom | Likely Cause | Solution |
|---------|------------|----------|
| "Could not read client certificate" | File path incorrect or permissions denied | Verify `GEOLIBRE_HTTP_CLIENT_CERT` path and file readability |
| "invalid password" | Wrong PKCS-12 password | Check `GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD` value |
| Server rejects connection | CA not trusted | Set `GEOLIBRE_HTTP_CA_CERT` to your enterprise root CA |
| Certificate not sent | Server does not request mTLS | Verify server configuration requires client certificates |

---

## Summary

- **Three environment variables** control mTLS: `GEOLIBRE_HTTP_CA_CERT` (optional CA trust), `GEOLIBRE_HTTP_CLIENT_CERT` (required), and `GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD` (for PKCS-12).
- **Two formats supported**: PEM (no password) and PKCS-12 (password-protected).
- **Singleton client**: Certificate is loaded once at startup in [`apps/geolibre-desktop/src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/src/lib.rs) and reused for all HTTPS requests.
- **Automatic presentation**: Certificate is only sent when servers explicitly request it during TLS handshake, per [`docs/architecture.md`](https://github.com/opengeos/GeoLibre/blob/main/docs/architecture.md) lines 135-139.

---

## Frequently Asked Questions

### What file formats does GeoLibre accept for mTLS client certificates?

GeoLibre accepts **PEM files** containing a certificate chain plus unencrypted PKCS-8 private key, or **PKCS-12 files** (`.p12` or `.pfx`) with encrypted private keys. PEM files require no password variable; PKCS-12 files require `GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD`.

### Do I need to modify GeoLibre source code to enable mTLS?

No. Configuration is entirely environment-driven. Set the appropriate variables before launching the desktop application and restart. The native client in [`lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/lib.rs) reads these variables automatically.

### Will my client certificate be sent to every HTTPS server?

No. The TLS libraries (rustls or native-tls) only transmit the client certificate when a server explicitly requests one via a CertificateRequest message during the TLS handshake. Arbitrary servers never receive your certificate.

### Where are the environment variables processed in the GeoLibre codebase?

The variables are defined as constants and consumed in [`apps/geolibre-desktop/src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/src/lib.rs) (lines 680-940). The architecture and security model are documented in [`docs/architecture.md`](https://github.com/opengeos/GeoLibre/blob/main/docs/architecture.md) (lines 119-139).