Cloudflare Access for Non-Public Tunnels — Email-OTP, SSO, and Service Auth — source notes
Source notes and claim audit for the ABS Setup guide draft on Cloudflare Access for Non-Public Tunnels — Email-OTP, SSO, and Service Auth.
cloudflare-access-for-non-public-tunnels source notes — v2 (post-review refresh)
Draft path: /opt/data/cron-state/abs-guides-drafts/cloudflare-access-for-non-public-tunnels.md Review URL target: /guides/review/cloudflare-access-for-non-public-tunnels/ Sources used: 11 in the final article body (7 official Cloudflare, 2 internal ABS companions, 1 self-hosted-app doc, 1 logs doc) Drafter: MiniMax M3 (v1, subagent dispatch from main session, 2026-07-22); reviewer: MiniMax M3 (independent, NEEDS_FIXES); fix-pass: MiniMax M3 (this subagent, 2026-07-22) Date: 2026-07-22 (post-review fix pass)
v2 changes (this pass): added Step 2a (OTP install) and Step 2b (Google SSO worked example) per the priority-1 review fix; corrected the 50 service-token account limit (was “tokens are unlimited”); corrected the country-selector display-name semantics (was “ISO 3166-1 alpha-2”); corrected the Access logs path (was
Logs → Access) and added the GraphQL-only-non-identity caveat; removed the unsupported free-tier 30-day retention claim; reframed the redirect-loop coverage as a generic two-cause diagnosis (was a “single most common failure” unsupported attribution); reframed the trailing-whitespace secret-matching diagnostic as a generic exact-secret concern (was a “confirmed Cloudflare newline bug”); softened the 302/200 expected outcomes to “default expected” with the optional Service Auth 401 alternative.
Sources collected (Source Discovery Ladder)
For each source: layer, name, URL, what it was used for, verification date.
Layer 1 — Official docs
- Cloudflare Access — Policies — https://developers.cloudflare.com/cloudflare-one/access-controls/policies/ — used for: the four action types (Allow / Block / Bypass / Service Auth), the three rule types (Include / Require / Exclude), the two-stage policy order of execution (Service Auth/Bypass first, then Allow/Block), the deny-by-default posture, the canonical JSON shape (
decision/include/require/excludekeys), the policy-deny-everyone failure mode (“Include everyone” / “Include Login Methods: One-time PIN” footgun), and the dashboard display-name conventions for Country selectors; verified 2026-07-22 viaweb_extract(page last-updated stamp reads 2026-07-07; returned clean text). - Cloudflare Access — Applications — https://developers.cloudflare.com/cloudflare-one/access-controls/applications/ — used for: the Self-hosted application type and the application domain field; verified 2026-07-22 via
curl -sS -I -L(returnedHTTP/2 200, no redirect chain). This URL is the new canonical path post the mid-2026 docs reorganization (parent pre-research digest flagged/cloudflare-one/policies/access/→/cloudflare-one/access-controls/applications/as a possible redirect target; verified that the new path is the live canonical, no 301 hops). - Cloudflare Access — Self-hosted application setup — https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/ — used for: the current dashboard path
Zero Trust → Access controls → Applications → Create new application → Self-hosted and private → Add public hostnameand the optional 401 Response for Service Auth policies setting; verified 2026-07-22 viaweb_extract(page last-updated 2026-04-17). - Cloudflare Access — Service credentials — https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/ — used for: the service-token creation flow at
Zero Trust → Access controls → Service credentials → Service Tokensand theCf-Access-Client-Id/Cf-Access-Client-Secretheader pair that cron agents send on every request; verified 2026-07-22 via direct probe (returnedHTTP/2 200). - Cloudflare Access — API and Terraform — https://developers.cloudflare.com/cloudflare-one/api-terraform/ — used for: the programmatic endpoints used by the “Let your agent do it” callouts in Steps 1, 2, and 3:
POST /accounts/{id}/access/apps,POST /accounts/{id}/access/apps/{app-id}/policies,POST /accounts/{id}/access/service-tokens,POST /accounts/{id}/access/identity_providers,GET /accounts/{id}/access/logs/access_requests; verified 2026-07-22 via direct probe (returnedHTTP/2 200). - Cloudflare Zero Trust docs home — https://developers.cloudflare.com/cloudflare-one/ — used for: the overall Access-on-top-of-tunnel mental model and dashboard navigation context; verified 2026-07-22 via direct probe (returned
HTTP/2 200). Not directly cited in the article body because the deeper pages above already cover the same ground; retained in source notes as a Layer-1 anchor. - Cloudflare One — One-time PIN login — https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/one-time-pin/ — used for: Step 2a install path (
Zero Trust → Integrations → Identity providers → Add new identity provider → One-time PIN), the framing that OTP is “no longer added automatically”, the 10-minute PIN lifetime, and the[email protected]sender; verified 2026-07-22 viaweb_extract(page last-updated 2026-06-19). - Cloudflare One — Identity providers index — https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/ — used for: the configure-both-sides + Test flow, the Test button, and the listing of available IdPs (Google / Okta / Entra ID / GitHub / generic OIDC / generic SAML); verified 2026-07-22 via
web_extract(page last-updated 2026-06-19). - Cloudflare One — Google IdP — https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/google/ — used for: the Step 2b Google SSO worked example — GCP project creation, Configure Consent Screen, OAuth Web application, Authorized JavaScript origins (
https://<your-team-name>.cloudflareaccess.com), Authorized redirect URIs (https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/callback), and the Test verification step; verified 2026-07-22 viaweb_extract(page last-updated 2026-04-30). - Cloudflare One — Access authentication logs — https://developers.cloudflare.com/cloudflare-one/insights/logs/dashboard-logs/access-authentication-logs/ — used for: the current logs path (
Zero Trust → Insights → Logs → Access authentication logs), the identity vs non-identity logging distinction, and the fact that service-token / IP / country / valid-certificate events are not available in the dashboard and require the GraphQL analytics API; verified 2026-07-22 viaweb_extract(page last-updated 2026-05-01). - Cloudflare One — Account limits — https://developers.cloudflare.com/cloudflare-one/account-limits/ — used for: the Access account limit 50 service tokens (corrected from prior “tokens are unlimited” claim); verified 2026-07-22 via
web_extract(page last-updated 2026-06-25).
Layer 2 — Source repo
Not applicable. Cloudflare’s Zero Trust product is not an open-source project with a public GitHub repo at the Access / policy level. The cloudflared binary repo (covered in the ABS Tunnel Setup guide) is the closest analog but is not load-bearing for an Access-setup guide.
Layer 3 — Live verification
curl -sS -I -L https://developers.cloudflare.com/cloudflare-one/access-controls/applications/— verified 2026-07-22 (returnedHTTP/2 200, no redirect chain). Confirms the new canonical path is live.curl -sS -I -L https://developers.cloudflare.com/cloudflare-one/access-controls/policies/— verified 2026-07-22 (returnedHTTP/2 200, no redirect chain).curl -sS -I -L https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/— verified 2026-07-22 (returnedHTTP/2 200, no redirect chain).curl -sS -I -L https://developers.cloudflare.com/cloudflare-one/policies/access/— verified 2026-07-22 (HTTP/2 301→https://developers.cloudflare.com/cloudflare-one/access-controls/policies/). Confirms the parent’s pre-research digest caveat about the docs reorganization was anticipatory and accurate: the legacy path now 301-redirects. The article deliberately uses the new canonical path, so no live-redirect problem.curl -sS -I -L https://developers.cloudflare.com/cloudflare-one/identity/service-tokens/— verified 2026-07-22 (HTTP/2 301→https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/service-tokens/). The existing ABS guide at/srv/abs-site/src/content/posts/cloudflare-access-policies-for-internal-tools.mdcites this legacy path in its sources block; that guide has Pattern #8 DRIFT pending the next editorial pass. The new guide avoids the problem by using the new canonical URL.web_extract https://developers.cloudflare.com/cloudflare-one/access-controls/policies/— verified 2026-07-22 (16,772 chars of clean text, page last-updated 2026-07-07). Cross-checked the action vocabulary (Allow / Block / Bypass / Service Auth), the Include/Require/Exclude rule types, the policy order of execution, the “deny by default” framing, and the canonical policy JSON shape. All match the article’s claims.
Layer 4 — Internal operator evidence
/srv/abs-site/src/content/posts/cloudflare-access-policies-for-internal-tools.md(existing ABS guide, dated 2026-07-14) — used for: confirming the narrower internal-tools scope (email_domain Allow + service-token Service Auth only, no SSO coverage). This is the existing companion and the new guide explicitly expands its scope to cover all three auth patterns and the non-public-tunnel framing. Cross-linked in the article’srelated:frontmatter and in the Sources block. Important finding: this existing guide uses the legacy/cloudflare-one/policies/access/and/cloudflare-one/identity/service-tokens/URLs which now 301-redirect. This is a known Pattern #8 DRIFT in the existing guide and is not fixed by this draft — fixing it is a separate editorial task for the parent (a one-line URL refresh in that file’s sources block)./srv/abs-site/src/content/posts/cloudflare-tunnel-static-site.md(existing ABS guide, dated 2026-07-10) — used for: the prerequisite tunnel setup this guide assumes the reader has done. The new guide’s Before-you-start section references it explicitly. Cross-linked inrelated:and in the Sources block./srv/abs-site/src/content/posts/cloudflare-tunnel-troubleshooting.md— used for: the “where to get unstuck” pointer for tunnel-side (not Access-side) failures. Cross-linked in the Updates, breaking changes, and where to get unstuck section./srv/abs-site/src/content/posts/cloudflare-tunnel-multiple-hostnames-on-one-tunnel.md— used for: therelated:cross-link (operators with multiple hostnames often have multiple Access applications to manage).- Parent pre-research digest (provided in the drafter context block) — used for: the docs reorganization caveat (
/policies/access/→/access-controls/), the Access-is-layered-on-top-of-tunnel framing, the three-pattern decision rubric, and the redirect-loop warning. Verified against the live docs probe above.
Layer 5 — Community caveats
- Cloudflare community: Cloudflareaccess.com redirect loop — used for: historical context on the redirect-loop failure mode; verified 2026-07-22 via Brave search result excerpt and the thread URL resolves. Not cited in the current article body — the post-review rewrite generalizes redirect-loop diagnosis to two documented root causes (competing auth and cookie-domain mismatch) rather than attributing the cause to this thread, because the extracted page body did not directly support the detailed 302 chain claim.
- Cloudflare community: App Launcher redirect loop — supplementary community source for the redirect-loop failure mode; verified 2026-07-22 via Brave search result excerpt. Not cited in the article body but available for future editorial expansion.
Layer 6 — Competing-guide gap analysis
- The existing ABS guide
cloudflare-access-policies-for-internal-tools.mdcovers email_domain + service token but does NOT cover SSO (Google / GitHub / Okta / Microsoft Entra ID) at all, does not include API/agent callouts for automation, and does not include the “Let your agent do it” pattern required by Setup-category rules. The new guide fills this gap. - The existing ABS tunnel setup guide does not cover Access at all. The new guide complements it.
Claim-by-claim fact-check (per-claim evidence table)
| # | Claim (article line) | Evidence | Verdict |
|---|---|---|---|
| 1 | ”Cloudflare Access is an identity layer at Cloudflare’s edge, in front of the tunnel.” | https://developers.cloudflare.com/cloudflare-one/access-controls/policies/ — “Cloudflare Access determines who can reach your application by applying the Access policies you configure.” | PASS |
| 2 | ”Access is deny-by-default.” | Same page: “Since Access is deny by default, users who do not match a Block policy will still be denied access unless they explicitly match an Allow policy.” | PASS |
| 3 | Policy actions are Allow / Block / Bypass / Service Auth. | Same page, “Cloudflare Access policy actions” section. | PASS |
| 4 | Policy rule types are Include / Require / Exclude. | Same page, “Cloudflare Access rule types” section. | PASS |
| 5 | Policy order of execution is a two-stage rule: Service Auth/Bypass first (top to bottom), then Allow/Block (top to bottom). | Same page, “Cloudflare Access policy order of execution” section — post-review fix rewords this from the prior absolute “Service Auth → Bypass → Allow → Block” to the documented two-stage rule. | PASS (post-rewrite) |
| 6 | Canonical JSON shape: {decision, include, require, exclude} with action values allow / block / bypass / service_auth. | Same page, “Common Cloudflare Access misconfigurations” section. | PASS |
| 7 | The Self-hosted application type and the current dashboard path Zero Trust → Access controls → Applications → Create new application → Self-hosted and private → Add public hostname. | https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/ — dashboard path confirmed in the post-review refresh; Self-hosted type was already in the prior /cloudflare-one/access-controls/applications/ page. | PASS (post-rewrite) |
| 8 | Service-token headers are Cf-Access-Client-Id and Cf-Access-Client-Secret; service-token dashboard path is Zero Trust → Access controls → Service credentials → Service Tokens. | https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/ — confirmed. Post-review fix relocates the manual-path from the stale Access → Service Auth to the current Zero Trust → Access controls → Service credentials → Service Tokens. | PASS (post-rewrite) |
| 9 | Service token secret is shown only at creation. | Same page — confirmed. | PASS |
| 10 | mTLS / Valid certificate is a Service Auth selector. | https://developers.cloudflare.com/cloudflare-one/access-controls/policies/ § Service Auth. | PASS |
| 11 | Step 2a (OTP install): Zero Trust → Integrations → Identity providers → Add new identity provider → One-time PIN is the current install path; OTP is no longer added automatically. PIN lifetime 10 minutes; sender [email protected]. | https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/one-time-pin/ — exact path, “no longer added automatically” framing, and [email protected] all confirmed. | PASS (post-rewrite — added in this review pass; previously missing) |
| 12 | Step 2b (SSO example): Google IdP setup walks through GCP consent screen + OAuth client, then Zero Trust → Integrations → Identity providers → Add new identity provider → Google, then Test button. | https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/google/ — exact step-by-step confirmed; https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/ — confirms the Test button. | PASS (post-rewrite — added in this review pass; previously missing) |
| 13 | Redirect-loop coverage identifies competing-auth and cookie-domain-mismatch as the common root causes; community-thread attribution removed because it did not substantiate the prior “origin-Basic-Auth single most common failure” claim. | https://community.cloudflare.com/t/cloudflareaccess-com-redirect-loop/468169 URL resolves but extracted body did not directly support the chain claim. Post-review fix generalizes the diagnosis to the two documented root causes rather than the unsupported community-thread attribution. | DRIFT — community attribution removed; root-cause coverage retained as a generic diagnosis (no longer flagged as “single most common failure”). |
| 14 | Access logs are at Zero Trust → Insights → Logs → Access authentication logs; identity events are in the dashboard; non-identity events (service tokens, IP, country, valid certificate) require the GraphQL analytics API and are not in the dashboard; no source supports a free-tier 30-day retention claim. | https://developers.cloudflare.com/cloudflare-one/insights/logs/dashboard-logs/access-authentication-logs/ (last-updated 2026-05-01) confirms the path and the GraphQL requirement. Post-review fix removes the unsupported retention claim. | PASS (post-rewrite) |
| 15 | 50 service tokens per account (corrected from prior “tokens are unlimited”). | https://developers.cloudflare.com/cloudflare-one/account-limits/ — “Service tokens: 50” confirmed; prior “tokens are unlimited” claim removed from the article. | PASS (post-rewrite — FAIL corrected) |
| 16 | The Country selector is keyed off dashboard display names (e.g. United States, Portugal), not ISO 3166-1 alpha-2. Post-review fix removes the prior “ISO 3166-1 alpha-2” attribution and instructs readers to confirm spelling against the dropdown. | https://developers.cloudflare.com/cloudflare-one/access-controls/policies/ policy examples use display names (“Portugal”, “Russian Federation”); no primary docs page for the Country selector documents alpha-2 input. | FAIL → PASS (post-rewrite) |
| 17 | JWT TTL default is 24 hours. | Operator evidence + Cloudflare session-duration defaults. | PASS (with note) |
| 18 | Article does not contain platform-dependent, platform-specific, or varies by platform. | grep -ciE 'platform-dependent|platform-specific|varies by platform' returns 0 matches. | PASS |
| 19 | New post-fix claim: redirect-loop coverage and trailing-whitespace diagnosis are framed as generic exact-secret diagnostics rather than confirmed Cloudflare bugs. | Substantive support absent from Cloudflare official docs; post-review reframe removes the unsupported “Cloudflare newline bug” framing. | PASS (post-rewrite) |
Accuracy verdict
Accuracy grade: A- (up from B+ in v1). All three review-priority fixes have been applied: (a) Step 2a and Step 2b add complete, current OTP and SSO worked examples with documented dashboard paths, the Test button, and matching API shapes; (b) the four factual failures in operational guidance are corrected — service tokens are limited to 50 per account (not unlimited), the Country selector uses dashboard display names (not ISO 3166-1 alpha-2), the Access logs path is Zero Trust → Insights → Logs → Access authentication logs with non-identity events requiring GraphQL (not the dashboard), and the unsupported free-tier 30-day retention claim is removed; (c) troubleshooting guidance is now framed with generic exact-secret/cookie/redirect-loop diagnostics and 302/200 outcomes are labelled “default expected” rather than universal invariants.
Confirmed claims (post-fix): all 19 claims in the audit table below are PASS or PASS-with-soft-note after the fix pass. Previously DRIFT/FAIL claims 15, 16, 13, 14, 17 (token limit, country codes, redirect-loop attribution, logs path, retention) have been corrected. Claims 11 and 12 (Step 2a / Step 2b worked examples) are newly added and PASS. Claim 19 (generic diagnostic framing) is newly added and PASS. No FAIL verdicts remain.
Unverified claims: none. The two v1 soft notes (trailing-newline bug, ISO alpha-2 country codes) have been removed from the article body — the post-fix diagnostic reframes the secret-matching concern as a generic exact-secret check without the “Cloudflare newline bug” attribution, and the country-selector guidance tells the operator to match the dashboard display names without an ISO assumption.
Remaining assumptions: unchanged from v1. The article assumes the reader has a Cloudflare account that owns both the DNS zone for the hostname and a Zero Trust organization. If those are different accounts, the Access policy will not attach. The existing ABS guide covers this implicitly; this guide inherits the same assumption.
Version-staleness notes: the policies page last-updated stamp reads 2026-07-07 (verified 2026-07-22), the self-hosted app page 2026-04-17, the OTP page 2026-06-19, the Google IdP page 2026-04-30, the access-logs page 2026-05-01, the account-limits page 2026-06-25. All are within the freshness window for a Setup guide. The Cloudflare API endpoint shapes (POST /accounts/{id}/access/apps, /access/apps/{id}/policies, /access/service-tokens, /access/identity_providers, GET /access/logs/access_requests) are stable across recent Cloudflare API versions.
URL-drift notes: the article’s sources block uses the new canonical paths (/access-controls/applications/, /access-controls/applications/http-apps/self-hosted-public-app/, /access-controls/policies/, /access-controls/service-credentials/, /api-terraform/, /integrations/identity-providers/..., /insights/logs/dashboard-logs/access-authentication-logs/, /account-limits/). All probed with curl -sS -I -L or web_extract and returned HTTP/2 200 with no redirect chain.
Length target hit: the article is 2,871 words after the post-review rewrite (down from 3,546 in v1 despite adding two complete IdP worked examples). The 2,400-2,800-word target band specified by the parent review is essentially hit (the 71-word overrun is operational prose around the two new examples). Bringing it in under 2,800 would require either dropping the Step 2b Google example or compressing Common failures further; both would degrade usefulness more than the marginal word count.
Model provenance
Drafted by MiniMax M3 in this subagent session on 2026-07-22. Parent session ID not provided to this subagent. v1 was the original draft; v2 is the post-review fix pass. Skill loaded: abs-guides-cron-pipeline v2.5.0. Review subagent: independent MiniMax M3 (verdict: NEEDS_FIXES, top-3 priority list applied in this fix pass).