Skip to content

Authentik and protecting SaxDocs

Authentik is the SSO layer for homelab apps. It runs at auth.saxobroko.com.

SaxDocs login uses Cloudflare Access → Authentik OIDC. You get the same username/password prompt as other Authentik apps (not email one-time PIN).

Current status

Step Status
Cloudflare Access app for docs.saxobroko.com Live
Authentik OIDC identity provider in Cloudflare Live — named "Authentik"
Allow policy Live — any Authentik user
Matching OAuth2 provider in Authentik Live — slug cloudflare-access
WAF skip rules for auth + docs Done

Cloud Cursor cannot finish the Authentik step. Cloud agents have no route to 192.168.2.203 and auth.saxobroko.com API hits Cloudflare bot challenges from outside Australia. Run the setup script from your PC or TrueNAS shell instead.

Client ID: Zero Trust → Integrations → Identity providers → Authentik (or Settings → Authentication). Cloudflare never shows an existing client secret after save — only ********. To get a usable secret, click Rotate secret / Regenerate in that IdP panel (or rotate via API), copy the new value immediately, then paste the same secret into Authentik. Store in Vaultwarden too.

Login flow

Browser → docs.saxobroko.com
       → Cloudflare Access (Authentik IdP only)
       → auth.saxobroko.com login (username + password)
       → back to docs

Same credentials as Homepage / dash when those use Authentik.

One-time Authentik setup

Create an OAuth2/OpenID provider that matches the Cloudflare IdP.

Option A — Authentik UI (easiest)

  1. Open auth.saxobroko.comAdmin interface
  2. ApplicationsCreate with Provider
  3. Provider type: OAuth2/OpenID Provider
  4. Settings:
  5. Name: Cloudflare Access
  6. Slug: cloudflare-access (must match JWKS URL in Cloudflare)
  7. Client type: Confidential
  8. Grant types: authorization_code (required — Cloudflare uses the auth-code flow)
  9. Client ID / Secret: copy from Cloudflare Zero Trust → Authentik login method
  10. Redirect URI: https://saxobroko.cloudflareaccess.com/cdn-cgi/access/callback
  11. Authorization flow: default provider authorization flow
  12. Invalidation flow: default provider invalidation flow
  13. Signing key: any active certificate
  14. Scopes (under Advanced protocol settings): add openid, email, and profile
  15. Include claims in ID token: enabled (checked)
  16. Save

Also confirm your Authentik user has an email address set under Directory → Users — Cloudflare Access requires it.

On your Windows PC or TrueNAS (not Cloud Cursor):

cd /path/to/SaxDocs   # or clone the repo
export AUTHENTIK_URL='http://192.168.2.203:30140'
export AUTHENTIK_TOKEN='your-authentik-admin-api-token'
export AUTHENTIK_CLIENT_ID='from-cloudflare-zero-trust-authentik-idp'
export AUTHENTIK_CLIENT_SECRET='from-cloudflare-zero-trust-authentik-idp'
./scripts/setup-authentik-provider.sh

Get an admin API token in Authentik: Admin → Directory → Tokens → Create (or use an existing token).

PowerShell on Windows (Git Bash or WSL):

$env:AUTHENTIK_URL='http://192.168.2.203:30140'
$env:AUTHENTIK_TOKEN='your-token'
$env:AUTHENTIK_CLIENT_ID='from-cloudflare'
$env:AUTHENTIK_CLIENT_SECRET='from-cloudflare'
bash scripts/setup-authentik-provider.sh

Option C — Re-run Cloudflare script

If starting fresh:

export CLOUDFLARE_API_TOKEN='token-with-zero-trust-edit'
./scripts/setup-cloudflare-access.sh

Then complete Option A or B with the printed client credentials.

Verify

  1. Incognito → docs.saxobroko.com
  2. Should land on Authentik login (username/password), not MkDocs
  3. After login → SaxDocs loads
  4. GitHub Actions deploy still works (uses API token, not browser Access)

Cloudflare Zero Trust → Access → Applications → SaxDocs → Test on the Authentik login method.

What uses Authentik today

App URL Notes
Homepage dash.saxobroko.com Forward auth / proxy
SaxDocs docs.saxobroko.com Cloudflare Access + OIDC
Authentik auth.saxobroko.com Must stay reachable for callbacks

Credentials for Authentik admin live in Vaultwarden. Do not commit passwords to this repo.

Troubleshooting

Cloudflare challenge / JS check instead of login: Turn off Bot Fight Mode for the zone (Zero Trust → Settings → Network, or zone Security). Bot Fight Mode cannot be skipped with WAF rules and blocks the Access login handshake.

Authentik shows "Not Found": Cloudflare was pointing at the wrong authorize URL (/application/o/cloudflare-access/authorize/ — 404). Correct auth URL is the generic endpoint below. If you still see Not Found, hard-refresh or use incognito — an old tab may have cached the bad redirect.

Script returns 403 Forbidden: The AUTHENTIK_TOKEN is wrong, expired, or lacks permissions. Create a fresh token in Authentik Admin → Directory → Tokens and App passwords → Create — set Intent to API Token, assign your admin user, then copy the secret value shown once (not the Identifier label shown later). Export it and re-run without sudo:

export AUTHENTIK_TOKEN='the-long-random-string-from-create-screen'
curl -H "Authorization: Bearer $AUTHENTIK_TOKEN" http://192.168.2.203:30140/api/v3/root/config/

If that curl returns JSON with a version number, the token works. If it returns 403, create another token.

Easier alternative — skip the script: Admin → Applications → Cloudflare Access → Provider → paste Client ID, Client Secret, redirect URI, and scopes from below.

"User email was not returned" after Authentik login: Cloudflare got no email claim in the OIDC token. In the Authentik provider, under Advanced protocol settings, add scopes openid, email, profile, and enable Include claims in ID token. Also check Directory → Users → your account has an email address filled in. Save the provider, then retry incognito.

export AUTHENTIK_URL='http://192.168.2.203:30140'
export AUTHENTIK_TOKEN='your-token'
export AUTHENTIK_CLIENT_ID='from-cloudflare'
export AUTHENTIK_CLIENT_SECRET='from-cloudflare'
./scripts/setup-authentik-provider.sh

Login loop: Authentik (auth.saxobroko.com) must not itself be behind Cloudflare Access.

IdP test fails in Cloudflare: Slug must be cloudflare-access, redirect URI must match exactly (no trailing slash), client ID/secret must match both sides.

403 challenge instead of login: Usually bot/challenge from curl — test in a real browser from Australia.

OIDC endpoints (reference):

Setting URL
Auth URL https://auth.saxobroko.com/application/o/authorize/
Token URL https://auth.saxobroko.com/application/o/token/
JWKS https://auth.saxobroko.com/application/o/cloudflare-access/jwks/
Redirect https://saxobroko.cloudflareaccess.com/cdn-cgi/access/callback

Official guide: Authentik + Cloudflare Access

Content hygiene

Access stops casual browsing. It is not encryption at rest.

  • Avoid full street addresses in markdown (defense in depth)
  • Finance screenshots remain in git history on GitHub
  • Page history links point to public GitHub commits