- Shell 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| pia-proxy.sh | ||
| README.md | ||
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)
- Settings → Network Settings → Manual proxy configuration.
- HTTP Proxy:
<dns>Port443. - Tick "Also use this proxy for HTTPS".
- 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.jsoninside the project folder — considerchmod 600.
Files
pia-proxy.sh— main script (login + test + print credentials)README.md— this guide