# CSP Allowlists for External Tile Hosts in Tauri vs Web Builds: A Complete Guide

> Learn the exact CSP allowlists needed for external tile hosts in Tauri desktop and web builds. Discover how GeoLibre manages these essential security configurations for seamless integration.

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

---

**GeoLibre requires `connect-src` and `img-src` CSP entries in Tauri desktop builds, while web builds rely on CORS headers or the tile worker's allowlist instead.**

GeoLibre loads raster tiles through **MapLibre GL JS**. Depending on your target platform, securing external tile sources follows fundamentally different paths. This guide breaks down exactly what allowlists you need to configure for **Tauri desktop builds** versus **web browser builds**, with precise file paths and working code examples from the opengeos/GeoLibre repository.

## How Tauri Desktop Builds Handle External Tiles

In the **desktop (Tauri) build**, the application runs inside a native webview. The **Content-Security-Policy (CSP)** defined in [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) serves as the sole gatekeeper for all external resources. Unlike browsers, the Tauri webview **does not enforce CORS** — the CSP entirely controls what tile servers MapLibre can reach.

### Required CSP Directives

Two directives control tile fetching:

- **`connect-src`** – governs XHR/fetch requests MapLibre uses to retrieve tile data
- **`img-src`** – governs `<img>`-style requests used for raster tiles

The current Tauri CSP configuration lives in [[`apps/geolibre-desktop/src-tauri/tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/tauri.conf.json)](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/tauri.conf.json):

```text
connect-src 'self' ipc: http://ipc.localhost asset: data: blob: https:
               http://asset.localhost http://127.0.0.1:* http://localhost:*
               wss://collab.geolibre.app ws://127.0.0.1:* ws://localhost:*
img-src      'self' asset: data: blob: https: http://asset.localhost

```

### Adding a New External Tile Host

Any tile server not covered by `https:` or the explicit `http://asset.localhost` entry must be added to both directives. For example, to enable **OpenPlanetaryMap** tiles:

```text
connect-src … https://s3.us-east-2.amazonaws.com/opmmarstiles …
img-src      … https://s3.us-east-2.amazonaws.com/opmmarstiles …

```

Here is the complete configuration pattern:

```json
// apps/geolibre-desktop/src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "csp": "default-src 'self'; connect-src 'self' https://my.tileserver.com …; img-src 'self' https://my.tileserver.com …"
    }
  }
}

```

## How Web Builds Handle External Tiles

In the **web (browser) build**, GeoLibre is served as static files (via `npm run build` → `apps/geolibre-desktop/dist/`). The client bundle contains **no hard-coded CSP**. Instead, security is handled at the HTTP server layer through **CORS headers** or GeoLibre's **tile worker proxy**.

### Option 1: CORS-Enabled Tile Servers

If the external tile server sends appropriate `Access-Control-Allow-Origin` headers, no client-side configuration is required. The browser permits the request automatically.

### Option 2: Worker Proxy for CORS-Restricted Sources

If the tile server lacks CORS headers, GeoLibre routes requests through its **tiles worker** at [[`workers/tiles/src/allowlisted-fetch.ts`](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/allowlisted-fetch.ts)](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/allowlisted-fetch.ts). This worker acts as a same-origin proxy.

Add your host to the worker's allowlist:

```ts
// workers/tiles/src/allowlisted-fetch.ts
export const ALLOWLISTED_PREFIXES = [
  "https://s3.us-east-2.amazonaws.com/opmmarstiles/",
  "https://my.tileserver.com/",   // ← new entry
];

```

The worker's entry point at [`workers/tiles/src/index.ts`](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/index.ts) handles the actual CORS-free proxying logic.

## Side-by-Side Comparison

| Build Type | Security Mechanism | Configuration Location | Key Requirement |
|------------|-------------------|------------------------|---------------|
| **Tauri desktop** | CSP headers in webview | [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) | Explicit `connect-src` and `img-src` entries per host |
| **Web browser** | CORS headers or worker proxy | HTTP server or [`workers/tiles/src/allowlisted-fetch.ts`](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/allowlisted-fetch.ts) | Server CORS headers **or** worker allowlist entry |

## Practical Implementation: Adding a Custom Tile Source

Once your allowlists are configured, define the layer in your GeoLibre application. The pattern in [`apps/geolibre-desktop/src/lib/layers.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/layers.ts) demonstrates standard raster tile integration:

```ts
const layer = {
  id: "my-external-tiles",
  type: "raster",
  source: {
    type: "raster",
    tiles: ["https://my.tileserver.com/{z}/{x}/{y}.png"],
    tileSize: 256,
  },
};
store.addLayer(layer);

```

## Key Files Reference

- **Tauri CSP configuration** – [`apps/geolibre-desktop/src-tauri/tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/tauri.conf.json)
- **Tile worker allowlist** – [`workers/tiles/src/allowlisted-fetch.ts`](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/allowlisted-fetch.ts)
- **Tile fetching logic** – [`workers/tiles/src/index.ts`](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/index.ts)
- **Layer creation patterns** – [`apps/geolibre-desktop/src/lib/layers.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/layers.ts)

## Summary

- **Tauri builds** require explicit CSP allowlists in [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) — no CORS enforcement exists in the webview
- **Web builds** defer to CORS headers or the tile worker proxy — no client CSP is embedded
- Add external hosts to both `connect-src` and `img-src` for Tauri compatibility
- Use `ALLOWLISTED_PREFIXES` in the worker when CORS headers are unavailable
- Always verify tile URLs use the correct protocol (`https:` vs `http:`) in your CSP entries

## Frequently Asked Questions

### Does GeoLibre support wildcard CSP entries for all HTTPS tile servers?

The `https:` scheme source allows any HTTPS origin in `connect-src` and `img-src`, which covers most commercial tile providers. However, specific HTTP hosts require explicit entries. Review your [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) to confirm the wildcard is present and add individual hosts as needed for non-HTTPS sources.

### Why does my tile layer work in browser but fail in Tauri desktop?

Browsers enforce CORS, which many tile servers support. Tauri's webview ignores CORS and relies entirely on CSP. Check that your tile host appears in both `connect-src` and `img-src` directives within [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json), not just as a `https:` wildcard.

### How do I debug CSP violations in Tauri?

Launch your Tauri app with developer tools enabled. CSP violations appear in the console with specific blocked URLs. Cross-reference these with your [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) entries — the violation message indicates which directive blocked the request.

### Can I use environment variables for dynamic CSP allowlists in Tauri?

Tauri's CSP is static JSON configuration. For dynamic hosts, you must rebuild with updated [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) or implement a middleware proxy within your Rust backend that routes tile requests through a known-safe origin covered by your base CSP.