Skip to content

Cloudflare Access + PocketID Authentication

How external services are protected. PocketID (pocketid.monxas.casa) is the single OIDC identity provider; there are two distinct identity planes on top of it.

Identity model: two planes

Both planes authenticate against the same PocketID IdP, but they sit in different places:

  1. Cloudflare Access (edge plane). At the Cloudflare edge, an Access application challenges the request and delegates login to PocketID via the OIDC client named Cloudflare Access (PocketID acts as the IdP for CF Access). Used for services that have no authentication of their own. This plane leaves no trace in managed.caddy — it lives entirely in Cloudflare Zero Trust.
  2. PocketID OIDC nativo (per-app plane). Apps that speak OIDC talk directly to PocketID, each with its own OIDC client (Immich, Paperless, Karakeep, Audiobookshelf, Grafana, Vaultwarden, Piso Colón, Remote-Pulse Dashboard, …). This is real SSO inside the app — not "built-in / own auth". No Cloudflare Access policy and no Caddy forward_auth are involved.

forward_auth no está en uso

managed.caddy no contiene ningún bloque forward_auth hoy (2026-07-12). La auth no vive en Caddy: es OIDC nativo per-app + CF Access en el borde.

Architecture Overview

User → *.monxas.casa (Cloudflare DNS)
       → Cloudflare Tunnel (cloudflared LXC on Proxmox, ID 123)
       → Cloudflare Access checks authentication
           ├── Not authenticated → Redirect to PocketID (pocketid.monxas.casa)
           │                       User logs in with passkey/password
           │                       PocketID returns OIDC token to Cloudflare
           │                       Cloudflare sets session cookie (24h)
           └── Authenticated → Forward to origin service (192.168.0.208:PORT)

Components

Cloudflare Tunnel

  • Location: Proxmox LXC container ID 123 (192.168.0.x)
  • Tunnel name: monxas-casa-tunnel
  • Tunnel ID: d3d370db-f53c-4dcc-988e-880423e199d5
  • Config: Runs with remote token (routes managed in Cloudflare dashboard)
  • Service: /usr/bin/cloudflared --no-autoupdate tunnel run --token <token>
  • Route config: Each Docker container uses labels to register with the tunnel:
    labels:
      - tunnel.hostname=myservice.monxas.casa
      - tunnel.port=8080  # optional, defaults to container's exposed port
    

PocketID (OIDC Provider)

  • URL: https://pocketid.monxas.casa
  • Stack: /home/monxas/stacks/pocket-id/
  • Container: pocket-id-pocket-id-1 on port 1411
  • Image: ghcr.io/pocket-id/pocket-id:v2
  • Data: /home/monxas/stacks/pocket-id/data/ (SQLite DB + uploads)
  • Admin UI: https://pocketid.monxas.casa/settings/admin/oidc-clients

Cloudflare Access (Zero Trust)

  • Dashboard: https://one.dash.cloudflare.com/ (or via API)
  • Auth domain: monxas.cloudflareaccess.com
  • Account ID: 0e70e9f3f8ffabbdcf9f46b0307a074e
  • PocketID IdP ID: 4c6842b9-cf65-42f3-89dc-69bf517c00c0

Cloudflare API Authentication

Current Protected Services

PocketID OIDC clients (11)

Estos son los clientes OIDC registrados en PocketID. Cloudflare Access es el cliente del plano de borde; el resto son apps con OIDC nativo per-app.

OIDC client Plano
Cloudflare Access Edge (CF Access → PocketID IdP)
Vaultwarden OIDC nativo per-app
Karakeep OIDC nativo per-app
Audiobookshelf OIDC nativo per-app
Immich OIDC nativo per-app
Paperless OIDC nativo per-app
Grafana OIDC nativo per-app
Remote-Pulse Dashboard OIDC nativo per-app
wp-pulse OIDC nativo per-app
wp-pulse-app OIDC nativo per-app
Piso Colón OIDC nativo per-app

Protected by Cloudflare Access + PocketID (edge plane)

Apps sin auth propia; el login lo fuerza CF Access en el borde vía el cliente OIDC Cloudflare Access.

Service Domain Port
PairDrop airdrop.monxas.casa 3210
PaddleOCR ocr.monxas.casa 8103
Stirling PDF pdf.monxas.casa 8088
Markdown Tool md.monxas.casa 8111
Markdown API md-api.monxas.casa 8110
ntfy ntfy.monxas.casa 8082
Vera (OAP) vera.monxas.casa 8095

PocketID OIDC nativo (per-app plane)

Apps con SSO OIDC nativo contra PocketID (issuer pocketid.monxas.casa), cada una con su propio OIDC client. No es «built-in / own auth» y no llevan política de CF Access.

Service Domain Port OIDC client
Immich pics.monxas.casa 2283 Immich
Paperless paperless.monxas.casa 8000 Paperless
Karakeep bookmarks.monxas.casa 3333 Karakeep
Audiobookshelf podcasts.monxas.casa 13378 Audiobookshelf
Grafana grafana.monxas.casa 3030 Grafana
Vaultwarden pass.monxas.casa 8055 Vaultwarden
Piso Colón piso.monxas.casa Piso Colón
Remote-Pulse Dashboard Remote-Pulse Dashboard

Panel Piso Colón

piso.monxas.casa usa OIDC nativo PocketID (cliente Piso Colón, issuer pocketid.monxas.casa), no auth propia.

Protected by own built-in auth (no PocketID, no Access policy)

Apps que siguen con su propia auth interna, sin integrar PocketID.

Service Domain Port
Jellyfin jellyfin.monxas.casa 8096
Jellyseerr jellyseerr.monxas.casa 5055
Sonarr sonarr.monxas.casa 8989
Radarr radarr.monxas.casa 7878
Prowlarr prowlarr.monxas.casa 9696
Bazarr bazarr.monxas.casa 6767
Stash nopor.monxas.casa 9990
Change Detection changedetection.monxas.casa 5000

Legacy Access policies (pre-PocketID, using OTP)

Service Domain
Dozzle dozzle.monxas.casa
tunnel-auth auth.monxas.casa

How To: Add a New Service Behind PocketID

Step 1: Deploy the Docker container

In your docker-compose file, add the tunnel labels:

services:
  my-service:
    image: some-image:latest
    restart: unless-stopped
    ports:
      - 8XXX:8080
    labels:
      - tunnel.hostname=myservice.monxas.casa
      - tunnel.port=8XXX

Then start it:

docker compose up -d

Step 2: Add DNS record in Cloudflare

The tunnel should auto-create the DNS record, but if not, add a CNAME: - Name: myservice - Target: d3d370db-f53c-4dcc-988e-880423e199d5.cfargotunnel.com - Proxy: ON (orange cloud)

Step 3: Add route in Cloudflare Tunnel

Go to Cloudflare Zero Trust dashboard → Networks → Tunnels → monxas-casa-tunnel → Public Hostname tab → Add: - Subdomain: myservice - Domain: monxas.casa - Service: http://192.168.0.208:8XXX

Step 4: Create Cloudflare Access Application (via API)

ACCT="0e70e9f3f8ffabbdcf9f46b0307a074e"
IDP_ID="4c6842b9-cf65-42f3-89dc-69bf517c00c0"

cat > /tmp/cf_app.json << EOF
{
  "name": "My Service",
  "domain": "myservice.monxas.casa",
  "type": "self_hosted",
  "session_duration": "24h",
  "allowed_idps": ["$IDP_ID"],
  "auto_redirect_to_identity": true,
  "policies": [
    {
      "name": "Allow authenticated users",
      "decision": "allow",
      "include": [{"everyone": {}}],
      "precedence": 1
    }
  ]
}
EOF

curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/${ACCT}/access/apps" \
  -H "X-Auth-Key: <YOUR_API_KEY>" \
  -H "X-Auth-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d @/tmp/cf_app.json | python3 -m json.tool

Step 5: Grant user access in PocketID

Go to https://pocketid.monxas.casa/settings/admin/oidc-clients → Cloudflare Access client → Allowed Users → make sure your user (or "all users") is allowed.

Note: You only need to do Step 5 once (the Cloudflare Access OIDC client already exists). New Access applications all go through the same single OIDC client.

How To: Remove Access Protection from a Service

ACCT="0e70e9f3f8ffabbdcf9f46b0307a074e"
APP_ID="<app-uuid>"  # Get from listing below

curl -s -X DELETE "https://api.cloudflare.com/client/v4/accounts/${ACCT}/access/apps/${APP_ID}" \
  -H "X-Auth-Key: <YOUR_API_KEY>" \
  -H "X-Auth-Email: [email protected]" | python3 -m json.tool

How To: List All Access Applications

ACCT="0e70e9f3f8ffabbdcf9f46b0307a074e"

curl -s "https://api.cloudflare.com/client/v4/accounts/${ACCT}/access/apps" \
  -H "X-Auth-Key: <YOUR_API_KEY>" \
  -H "X-Auth-Email: [email protected]" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for app in data['result']:
    print(f\"{app['name']:20s} {app.get('domain','N/A'):35s} {app['id']}\")
"

How To: Update PocketID OIDC Client

If you need to change the OIDC client settings (e.g., add scopes): 1. Go to https://pocketid.monxas.casa/settings/admin/oidc-clients 2. Click "Cloudflare Access" 3. Current settings: - Client ID: 8c65bbe6-0c6e-4f07-b522-24f736fabf3d - Callback URL: https://monxas.cloudflareaccess.com/cdn-cgi/access/callback - Public client: OFF - PKCE: ON - Require re-auth: OFF

PocketID OIDC Endpoints

Endpoint URL
Discovery https://pocketid.monxas.casa/.well-known/openid-configuration
Authorization https://pocketid.monxas.casa/authorize
Token https://pocketid.monxas.casa/api/oidc/token
JWKS https://pocketid.monxas.casa/.well-known/jwks.json
Userinfo https://pocketid.monxas.casa/api/oidc/userinfo

Troubleshooting

"You're not allowed to access this service" (403)

Your PocketID user is not in the allowed users list for the OIDC client. → Go to PocketID admin → OIDC clients → Cloudflare Access → Allowed Users → add your user or set to "all users"

Auth loop / redirect fails

  1. Check PocketID logs: docker logs pocket-id-pocket-id-1 --tail 50
  2. Verify callback URL matches: https://monxas.cloudflareaccess.com/cdn-cgi/access/callback
  3. Check the OIDC client ID matches in both PocketID and Cloudflare

Service not reachable after adding Access

  1. Verify tunnel route exists in Cloudflare dashboard
  2. Check DNS CNAME points to tunnel
  3. Test direct access: curl http://192.168.0.208:PORT

PocketID is down

All Access-protected services will fail auth. Other services with built-in auth continue working.

cd /home/monxas/stacks/pocket-id && docker compose up -d
docker logs pocket-id-pocket-id-1 --tail 20

Reset PocketID completely

cd /home/monxas/stacks/pocket-id
docker compose down
rm -rf data/*
# Generate new encryption key
NEW_KEY=$(openssl rand -base64 32)
# Update .env with new ENCRYPTION_KEY=$NEW_KEY
docker compose up -d
# Visit https://pocketid.monxas.casa/setup to create admin account
# Then recreate the Cloudflare Access OIDC client and update Cloudflare IdP config

Backup & Recovery

PocketID data

  • Database: /home/monxas/stacks/pocket-id/data/pocket-id.db
  • Config: /home/monxas/stacks/pocket-id/.env
  • Docker Compose: /home/monxas/stacks/pocket-id/docker-compose.yml

Cloudflare Access config

Stored in Cloudflare's cloud. Can be recreated via API if needed. Key values to preserve: - PocketID IdP ID: 4c6842b9-cf65-42f3-89dc-69bf517c00c0 - OIDC Client ID: 8c65bbe6-0c6e-4f07-b522-24f736fabf3d - Account ID: 0e70e9f3f8ffabbdcf9f46b0307a074e

2026-06-01 — slicer protegido + token dedicado + limpieza

  • Nueva app Access: slicer.monxas.casa (OrcaSlicer) — self_hosted, IdP PocketID, policy allow-authenticated. app id 7fa5cf8c-9ea3-4319-8ce6-7426b4b702c5.
  • Token dedicado Claude: homelab-claude (user token, 53 chars). Scope: Access Apps&Policies (Edit), Access IdP (Read), Cloudflare Tunnel (Edit), Account Settings (Read) + DNS (Edit)/Zone (Read) en zonas. Guardado en secrets/cloudflare.sops.yamlcloudflare.claude_token. Revocable aislado.
  • Limpieza tokens (borrados): NPM (DNS, sin uso desde 2024-07, era Nginx PM), Argo Tunnel monxas.casa duplicado sin usar, Cloudflare Tunnel iarquitectos.com duplicado sin usar. Quedan 4 activos: media-server (homelab-ctl, ya tiene scope Access completo), Edit zone DNS monxas.casa (Caddy ACME), iarquitectos tunnel, Argo monxas tunnel.
  • ⚠️ La Global API Key se usó/expuso en una sesión 2026-06-01 → ROTAR en dashboard (My Profile → API Tokens → Global API Key → Change).