Obtain HTTPS-proxy credentials from a paid Private Internet Access account and use them in any external program. No browser extension or desktop app required.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-10 17:50:34 +02:00
pia-proxy.sh init 2026-08-10 17:50:34 +02:00
README.md init 2026-08-10 17:50:34 +02:00

PIA proxy without the extension

Obtain HTTPS-proxy credentials from a paid Private Internet Access account and use them in any external program. No browser extension or desktop app required.

How it works (short version)

The PIA extension authenticates to the proxy using a pair: token (proxy username) and tokenSecret (proxy password), obtained via a single HTTP POST:

POST https://www.privateinternetaccess.com/api/client/v2/token
     username=<PIA_USER>&password=<PIA_PASS>
→ {"token": "<128 hex chars>"}

Key trick (from main.js, the saveTokenForAuth function): the token returned by the API must not be used whole as the password. PIA splits it in half for proxy authentication:

rawToken  = 128 hex chars from the API
proxyUser = rawToken[ 0 : 64 ]   <- first half
proxyPass = rawToken[ 64 : 128 ] <- second half

The proxy server is an HTTPS proxy (HTTP CONNECT over TLS) on hosts of the form *.http-proxy.privateinternetbrowsing.com:443. Server list: https://serverlist.piaservers.net/proxy (JSON array of {name, iso, dns, ping, port:443}).

Never use your paid account credentials (x1234567 / password) directly on the proxy — they won't work. Always exchange them for a token first, then split it.

Quick start

# 1) list regions
./pia-proxy.sh --list

# 2) get credentials for CZ (default); prompts for username/password
./pia-proxy.sh
# or from env:
PIA_USER=p1234567 PIA_PASS=supersecret ./pia-proxy.sh NL

# 3) print HTTPS_PROXY (and friends) for sourcing into the current shell
PIA_USER=p1234567 PIA_PASS=supersecret ./pia-proxy.sh NL --env | source /dev/stdin

# 4) connectivity test against ifconfig.me
PIA_TEST=1 PIA_USER=... PIA_PASS=... ./pia-proxy.sh NL

# 5) verify token validity (exit 0=valid, 2=expired, 3=unknown)
PIA_USER=... PIA_PASS=... ./pia-proxy.sh NL --check

Files cached by the script:

  • .cache/servers.json — server list (refreshed after ~5 days)
  • .cache/token.json — last token

The cache path can be overridden with the PIA_CACHE_DIR env var.

Token expiry

The /client/v2/token API returns no expiry field (expires_*). To detect expiry, use --check or watch the proxy's HTTP status code:

  • HTTP 200 → token valid, proxy connected.
  • HTTP 407 Proxy Authentication Required → token expired; re-run the script (login API) to refresh it.
  • any other code → network / proxy-server issue (the token may still be valid).

Direct curl (without the script)

# token
curl -s -X POST https://www.privateinternetaccess.com/api/client/v2/token \
     --data-urlencode 'username=P1234567' \
     --data-urlencode 'password=heslo' \
     -o token.json

# split the token (PIA saveTokenForAuth)
read -r USER PASS < <(python3 - <<'PY'
import json
raw=json.load(open("token.json"))["token"]
h=len(raw)//2
print(raw[:h], raw[h:])
PY
)

# proxy test
curl -x "https://$USER:$PASS@czech-republic.http-proxy.privateinternetbrowsing.com:443" \
     https://ifconfig.me -v --proxy-insecure

--proxy-insecure is only needed if curl does not trust the proxy server's certificate.

Usage in common programs

curl

curl -x "https://$USER:$PASS@<dns>:443" https://ipinfo.io/json --proxy-insecure

(Note: -x http:// does NOT work — this is an HTTPS proxy, not a plain HTTP proxy.)

wget

https_proxy="https://$USER:$PASS@<dns>:443" wget -qO- https://ipinfo.io/ip

Node.js (undici ≥ 18, clean)

import { ProxyAgent, fetch } from "undici";
const agent = new ProxyAgent(
  `https://${USER}:${PASS}@czech-republic.http-proxy.privateinternetbrowsing.com:443`
);
console.log(await (await fetch("https://ipinfo.io/json", { dispatcher: agent })).json());

Python

Note: the requests + urllib3 stack does NOT support TLS-to-proxy (HTTPS proxy), only plain HTTP proxies. Three options:

A) curl via subprocess (recommended):

import subprocess, json
js = json.load(open("token.json"))
raw = js["token"]
USER, PASS = raw[:len(raw)//2], raw[len(raw)//2:]
out = subprocess.check_output([
    "curl", "-s", "-x",
    f"https://{USER}:{PASS}@czech-republic.http-proxy.privateinternetbrowsing.com:443",
    "https://ipinfo.io/json", "--proxy-insecure"
])
print(json.loads(out))

B) PySocks / SOCKS fallback: the PIA proxy is HTTPS, not SOCKS5, so a socks helper does not work for this endpoint.

C) Plain HTTP proxy (port 80, no TLS to proxy): PIA http-proxy servers also offer an unencrypted variant on port 80 when you don't want TLS-to-proxy:

http://$USER:$PASS@czech-republic.http-proxy.privateinternetbrowsing.com:80

This requests supports natively: proxies={"http": url, "https": url}.

Firefox (manual)

  1. Settings → Network Settings → Manual proxy configuration.
  2. HTTP Proxy: <dns> Port 443.
  3. Tick "Also use this proxy for HTTPS".
  4. In Proxy authentication: Username = token's first half, Password = second half.

System proxy (GNOME)

gsettings set org.gnome.system.proxy mode 'manual'
gsettings set org.gnome.system.proxy.https host '<dns>'
gsettings set org.gnome.system.proxy.https port 443
gsettings set org.gnome.system.proxy use-authentication true
gsettings set org.gnome.system.proxy.authentication-user  '<token-first-half>'
gsettings set org.gnome.system.proxy.authentication-password '<token-second-half>'
# to disable:
gsettings set org.gnome.system.proxy mode 'none'

System proxy (env vars for CLI tools)

export HTTPS_PROXY="https://<first-half>:<second-half>@<dns>:443"
export https_proxy="$HTTPS_PROXY"
export ALL_PROXY="$HTTPS_PROXY"     # supported by curl / undici

(Some tools need an equivalent of --proxy-insecure to accept the proxy cert.)

Summary of values

Field Value
Protocol HTTPS proxy (HTTP CONNECT over TLS)
Host *.http-proxy.privateinternetbrowsing.com
Alt IP ping field from the server list
Port 443 (or 80 for unencrypted HTTP proxy)
Username token[0:64] — first half of the token from /client/v2/token
Password token[64:128] — second half of the token
Server list https://serverlist.piaservers.net/proxy
Token API POST https://www.privateinternetaccess.com/api/client/v2/token

Security

  • Treat token / the split proxy credentials as passwords (they grant proxy access). The script stores them in .cache/token.json inside the project folder — consider chmod 600.

Files

  • pia-proxy.sh — main script (login + test + print credentials)
  • README.md — this guide