OIDC + CF Access auth flow¶
PocketID es Identity Provider único del homelab. Dos rutas de auth según la app.
PocketID — 11 OIDC clients activos (2026-07-12)¶
PocketID (
:1411en VM 208) tiene 11 clientes OIDC registrados. La tabla lista los principales/validados E2E; el resto son clientes internos de otros servicios.
| Cliente | Hostname | Estado E2E | Notas |
|---|---|---|---|
| Karakeep | bookmarks.monxas.casa |
✅ Login E2E validado | Auto-provisioning de usuarios |
| Grafana | grafana.monxas.casa |
✅ Login E2E validado | Mapping role via groups |
| Paperless-ngx | paperless.monxas.casa |
✅ Login E2E validado | OIDC social account |
| Vaultwarden | pass.monxas.casa |
🟡 Configurado, UI pendiente | SSO config en admin |
| Immich | pics.monxas.casa |
🟡 Configurado, UI pendiente | Auto-launch toggle |
| Audiobookshelf | podcasts.monxas.casa |
🟡 Configurado, UI pendiente | OpenID Connect |
| Cloudflare Access | monxas.cloudflareaccess.com |
✅ Backing ~31 apps (no verificado) | Sin email PIN |
Ver Creating an OIDC client para el procedimiento de alta.
Apps con OIDC nativo (Karakeep, Grafana, Paperless...)¶
sequenceDiagram
autonumber
actor User
participant CF as Cloudflare edge
participant CFT as cloudflared (LXC 123)
participant VIP as VIP .250 keepalived
participant Caddy as Caddy LXC 270/271
participant App as App (Grafana/Karakeep/Paperless)
participant PID as PocketID
User->>CF: GET https://grafana.monxas.casa
CF->>CFT: Tunnel (HTTP/2)
CFT->>VIP: https://192.168.0.250:443
VIP->>Caddy: TCP (primary)
Caddy->>App: reverse_proxy a VM 208:3030
App-->>User: 302 /login (no session)
User->>App: Click "Sign in with PocketID"
App->>PID: 302 /authorize?client_id=X&PKCE
PID-->>User: Login form (passkey o credenciales)
User->>PID: Auth OK
PID->>App: 302 /callback?code=AUTH
App->>PID: POST /api/oidc/token (auth_code + secret)
PID-->>App: access_token + id_token (JWT)
App->>PID: GET /api/oidc/userinfo
PID-->>App: {email, name, sub}
App->>App: Session created (sub_id linked to local user via email)
App-->>User: Logged in
Notas:
- Token exchange usa client_secret_basic (HTTP Basic auth) o client_secret_post. PocketID acepta ambos.
- PKCE obligatorio (pkce_enabled=1 en cliente PocketID).
- Email link: si email del JWT matchea local user → linkea sin crear duplicado. Si no, crea user nuevo (puede requerir promoción manual a admin, ver guides/creating-oidc-client.md).
Apps con login propio + CF Access perimeter (~31 apps mgmt, no verificado)¶
sequenceDiagram
autonumber
actor User
participant CF as Cloudflare edge
participant CFA as CF Access policy
participant PID as PocketID
participant CFT as cloudflared
participant App as App (Sonarr, Dashboard, Dockge...)
User->>CF: GET https://sonarr.monxas.casa
CF->>CFA: Check session cookie
alt Sin sesión CF Access
CFA->>PID: 302 /authorize (OIDC client "Cloudflare Access")
PID-->>User: Login (passkey)
User->>PID: Auth OK
PID->>CFA: code → token
CFA-->>User: Set session cookie (24h)
end
CFA->>CFT: Forward + headers JWT
CFT->>App: HTTPS via tunnel
App->>App: Auth own (Sonarr API key cookie, etc.)
App-->>User: App UI (sesión propia)
Notas: - Sesión CF Access dura 24h, compartida entre las apps protegidas (~31, no verificado). - App sigue requiriendo su propio login (CF Access es perimeter, no SSO de app). - No email PIN — PocketID es único IdP en CF Zero Trust → Settings → Authentication.
Apps que SE QUEDAN FUERA de ambos¶
- PocketID itself — sería loop infinito si se autoprotege.
- monxas.casa apex — landing público.
- cors, kiwix, loki, rag — públicas o bearer-token API.
Routing cross-cutting¶
graph LR
subgraph "Internet"
U[User]
end
subgraph "Cloudflare"
E[CF edge]
A[CF Access
31 apps]
end
subgraph "Homelab pmx-50"
VIP{{VIP .250
keepalived}}
C1[Caddy LXC 270
.247]
VM[VM 208 backends
~75 containers]
PID[PocketID
:1411]
end
subgraph "Homelab pmx-51"
CFT[cloudflared
LXC 123]
C2[Caddy LXC 271
.248]
end
U -->|HTTPS| E
E -->|31 apps| A
A -->|OIDC| PID
E -->|tunnel| CFT
CFT --> VIP
VIP -.master.-> C1
VIP -.backup.-> C2
C1 --> VM
C2 --> VM
VM -->|reverse_proxy| PID
style PID fill:#9c27b0,color:#fff
style A fill:#ff6b6b,color:#fff
style VIP fill:#ffd43b
Decisiones que importan¶
| Decisión | Por qué |
|---|---|
| PocketID en VM 208 Docker (no LXC propio) | Stack ~/stacks/pocket-id/, DB SQLite local. Compatible con backups dockge habituales. Sin tunnel.* labels: NO se mete en routing automation (acceso via pocketid.monxas.casa por DNS + Caddy general rule). |
| CF Access NO detrás de Caddy LXC | CF Access intercepta en edge antes de tunnel — Caddy nunca ve apps protegidas hasta que CF Access aprueba. |
| Caddy LXC full-routing (post-F4.f, 2026-05-20) | LXC 270/271 son source-of-truth — importan managed.caddy (host:port targets a 192.168.0.208) + LE wildcard cert vía DNS-01. El container Caddy en VM 208 fue eliminado. Si VM 208 cae, backends caen pero el ingress (LXC 270/271) sigue respondiendo (puede servir error pages custom). |
| 24h session CF Access + token PocketID stateless | Balance UX (no re-login frecuente) vs security (limited blast radius si cookie leaked). |