---
title: "Python web: check access on the server"
description: "Run a local Flask app that protects a real CSV download without exposing license credentials to the browser."
slug: "/docs/v1/tutorials/python/web"
section: "Practical tutorials"
order: 1003
audience: "all"
level: "beginner"
last_updated: "2026-10-26"
version: "v1"
related: ["/docs/v1/tutorials/python", "/docs/v1/sdks/python", "/docs/v1/sdks/capabilities"]
draft: false
layout: "guide"
---

## What this web example licenses

This is **one customer's Python server installation**, opened in a browser. KDPika licenses that server; your web app still controls who may sign in. A browser tab is not a licensed device, and the Python SDK does not replace your website's user accounts.

It is a complete local learning example, not an internet-facing multi-tenant SaaS authentication product. Run it on `127.0.0.1`. For a real multi-customer service, authenticate each user and map that user to the correct server-side tenant/license/state; never accept a caller-supplied license identity as authorization. [Application architectures](/docs/v1/start/use-cases).

## 1. Prepare the project

[Download and extract the Python projects](/docs/downloads/kdpika-python-projects-1.0.0.zip). Create the tutorial product/plan/customer/Sandbox license in [shared setup](/docs/v1/tutorials/python#make-your-first-test-license). The normal software plan should include `csv_export` with usage credits off.

Create and activate a virtual environment as shown in [the desktop guide](/docs/v1/tutorials/python/desktop#1-install-python-and-the-sdk), then install the example requirements:

```bash
python -m pip install -r requirements.txt
```

This installs the official SDK and Flask in your local project. It does not change KDPika's PHP hosting or add Flask to the SDK's own dependencies.

Dashboard example: What are you licensing?

Open: Products → New product

Example data only; use your own real dashboard.

Product name: Orbit Web

Slug: orbit-web

Description: A small app that exports a CSV file.

Platform: Web

License prefix: ORBT — 2–8 letters or numbers.

Buttons: Create product

Use a separate test product. The name and App ID shown here are examples, not real account data.

## 2. Start the server

macOS/Linux:

```bash
export KDP_APP_ID="app_YOUR_PUBLIC_ID"
export KDP_ENVIRONMENT="SANDBOX"
python web.py
```

Windows PowerShell:

```powershell
$env:KDP_APP_ID="app_YOUR_PUBLIC_ID"
$env:KDP_ENVIRONMENT="SANDBOX"
python web.py
```

On first start, enter the test license key privately in the server terminal and its matching customer email. Then the terminal prints a random **local app access code**. This code is for this local web app, not your KDPika password or license key. Keep it private.

## 3. Open the web app and export

1. Visit `http://127.0.0.1:5000` on that computer.
2. Enter the local app access code printed by this run.
3. Type a message and choose **Download CSV**. The server checks the signed license and feature immediately before creating the file.
4. The browser receives the CSV, not the activation token, raw key, fingerprint or signed customer payload.
5. Choose **Sign out** to end the app session. This does not revoke the installed server license.

Restarting the local example generates a new app access code/session secret and signs its web users out. The SDK installation state stays in the same private product/environment folder. A production deployment needs stable server session secrets, HTTPS/secure cookies and real user authorization/rate limits. Do not expose Flask's development server to the public internet.

## 4. Follow the request

| Stage | What happens |
| --- | --- |
| App sign-in | A CSRF-protected local form establishes this example's app session |
| Export request | The backend checks the app session and CSRF, validates the text and asks the SDK for access |
| License result | The SDK verifies signature, product/environment, device binding and signed deadlines |
| Feature guard | The backend checks `csv_export`; hiding a browser button alone is never protection |
| Download | Only allowed work writes and returns the CSV; responses are private/no-store |

The same `common.py` from the desktop project contains the feature guard. The difference is **where it runs**: in the Python backend instead of a customer desktop window.

{{sample:python-projects/web.py}}

## 5. Add the advanced models

| Requirement | Implementation |
| --- | --- |
| Device limits | Configure the software plan or per-license override. The licensed installation here is the server, not each visitor |
| Advanced hardware matching | Configure the product policy; the Python SDK collects hashes on its server. Containers/VM identity changes need a deliberate deployment policy |
| Offline access | `check()` can use a verified normal cache within signed deadlines. Do not use this as evidence that a browser user's own subscription is paid |
| Floating seats | The SDK maintains a lease for this server process. A single shared Python client does not create one seat per signed-in browser user |
| Credits | Use [the durable credit export](/docs/v1/tutorials/python/credits) as backend job logic; authenticate and authorize the user/job before calling it. The starter route refuses credit-based exports until you deliberately integrate charging |
| Portal and branding | Configure [the hosted portal](/portal-settings), then link to its real sign-in URL from your app. Never put a customer key/token in that URL |
| Plan edits and personal overrides | Use Plans or the customer's license in the KDPika dashboard; the SDK reads the effective signed result |
| Audit/history | Review eligible server-side licensing/account audit events in KDPika. Your web app needs its own user/action audit trail without secrets |

## 6. Deploy deliberately

The example runs a **single process** with the reloader/debugger off. For production, use a maintained production server and existing application authentication. Decide whether each worker/server is one licensed installation or whether licensing is handled by a dedicated trusted backend. Do not initialize heartbeat workers before forking or copy one machine's activation directory across containers.

Persist private SDK state across restarts, restrict its filesystem access and keep Sandbox and Live separate. In a hosted web app, use server-side HTTPS requests; do not send a management key or native hardware collector to browser JavaScript. Start each client after its process starts and close it on shutdown. Stop protected work when access is refused or its signed lease expires.

## 7. Verify before going live

- Without the app session, submitting an export is refused.
- With a missing/incorrect CSRF value, the request is refused before licensed work.
- With an eligible signed license and `csv_export`, the CSV is downloaded.
- With a disabled feature, expired/refused license or metered plan on this starter route, no free export is generated.
- The browser never receives a raw key or activation/session token from the SDK.

These controls are tested at code/request level; no visual or production deployment test of the sample Flask app is claimed. The live KDPika documentation page is deployed separately.

[Python feature map](/docs/v1/tutorials/python) · [Desktop app](/docs/v1/tutorials/python/desktop) · [Usage-credit job](/docs/v1/tutorials/python/credits).
