Image for Cloudflare Command Center: Domains, DNS, Zero Trust, and Tunnels from Beginner to Expert Part 10: Cloudflare Access. Protect Internal Apps Without Exposing Them to the Internet
Technology Jul 31, 2026 • 17 min read

Cloudflare Command Center: Domains, DNS, Zero Trust, and Tunnels from Beginner to Expert Part 10: Cloudflare Access. Protect Internal Apps Without Exposing Them to the Internet

Learn how Cloudflare Access locks down internal apps, admin panels, and staging sites using identity-based policies. No VPN required.

Share:
Lee Foropoulos

Lee Foropoulos

17 min read

Continue where you left off?
Text size:

Contents

Part 9 built out Cloudflare Tunnel from scratch: the connector, the routing, the private network configuration that keeps your origin server completely off the public internet. If you followed that walkthrough, you have a working tunnel. Traffic flows from a public subdomain through Cloudflare's edge to your origin, and your origin has no open inbound ports. That's a solid foundation. The problem is that anyone who knows your subdomain can still reach whatever sits behind it. A tunnel routes traffic. It doesn't decide who deserves to receive it.

That's where Cloudflare Access comes in. Access is the identity gate that sits in front of your applications and refuses to pass traffic until it knows who's asking. Not just where the request came from. Who sent it.

This part covers Access end to end: how it works, how to configure your first application, how to connect identity providers, how to write policies that actually enforce something, and how to apply all of it to three real internal apps you're probably already running.

What Is Cloudflare Access and Why Does It Matter?

The Problem With Traditional Perimeter Security

The old model of network security was built on a simple idea: keep the bad stuff out, trust everything inside. You drew a perimeter around your infrastructure, put a firewall on the edge, and handed out VPN credentials to anyone who needed to get in. Once someone had those credentials and was inside the perimeter, the network largely trusted them. The assumption was that the perimeter held.

That assumption hasn't aged well. VPN credentials get stolen, phished, and shared. Contractors get access they don't need and keep it longer than they should. A single compromised machine inside the perimeter can move laterally across the network because the perimeter model doesn't evaluate trust continuously. It evaluates it once, at the gate, and then mostly forgets about you.

82%
of breaches involve credentials, not zero-day exploits (Verizon DBIR)

The perimeter didn't fail because the technology was bad. It failed because the threat model it was designed for doesn't match how people work or how attackers operate anymore.

Access as the Zero Trust Front Door

Cloudflare Access is a reverse proxy that enforces identity before traffic reaches your application. Every request to a protected resource hits Cloudflare's edge first. Access intercepts it, checks whether the user has a valid session and meets your policy requirements, and only then forwards the request to your origin. The origin never sees unauthenticated traffic.

This is Zero Trust Network Access (ZTNA) in practice. The model assumes no user or device should be trusted by default, regardless of network location. Trust is earned per-request, based on verified identity and policy evaluation.

Server room with blue lighting and organized cable management
Access sits at Cloudflare's edge, intercepting every request before it reaches your origin.

Access works in front of self-hosted apps, SaaS applications, and internal tools. It doesn't require firewall rule changes on your origin. It doesn't require a VPN client on the user's machine. It requires an identity provider and a policy. That's it.

The perimeter model trusted your location. Zero Trust trusts your identity, and it checks every time.

This article walks through Access applications, identity provider configuration, policy writing, session control, and audit logs. By the end, you'll have a working identity gate in front of your internal tools.

How Cloudflare Access Works Under the Hood

The Request Flow Explained

Understanding what actually happens during an Access-protected request makes troubleshooting dramatically easier and policy design more intuitive. The flow has a few distinct steps, and each one is worth knowing.

A user opens their browser and navigates to admin.yourdomain.com. That request hits Cloudflare's edge, which recognizes the subdomain as an Access-protected application. Before anything reaches your origin, Access intercepts the request and checks for a valid session cookie. If no cookie exists, the user is redirected to the Access login page, where they authenticate through your configured identity provider.

Once authentication succeeds, Access evaluates the user's identity against your policy rules. Email domain, group membership, IP address, device posture: any combination of attributes you've configured. If the evaluation passes, Access issues a signed JWT token and sets a session cookie in the user's browser. That token contains identity claims your application can optionally read. The request is then forwarded to your origin with the JWT attached as a request header.

Office technology setup showing monitors and networking equipment
The full request lifecycle: browser to Access edge to identity check to origin, with JWT issued on success.

On subsequent requests within the session window, Access validates the existing cookie without requiring a full re-authentication. When the session expires, the user authenticates again. The origin never receives a request that hasn't passed the identity check.

Where Tunnels and Access Intersect

Access and Cloudflare Tunnel are separate products that work exceptionally well together. A Tunnel creates an outbound-only connection from your origin server to Cloudflare's edge, which means your origin has no publicly accessible ports. Access then sits in front of the subdomain that the Tunnel serves. The result is an application that's completely invisible to the public internet and identity-gated at the edge.

Access Without a Tunnel

You don't need a Tunnel to use Access. If your application has a public IP or URL, Access can still gate it with an identity check. The origin will be technically reachable without the gate in that case, so pairing Access with a Tunnel is the stronger configuration for sensitive internal tools. For SaaS applications, a Tunnel isn't applicable at all.

The JWT that Access issues is worth paying attention to if you control the application code. Your app can read the Cf-Access-Jwt-Assertion header, verify the token against Cloudflare's public keys, and extract identity claims like the user's email. This lets your application know who's logged in without building its own authentication layer.

Setting Up Your First Access Application

Everything in Cloudflare Access lives inside the Zero Trust dashboard, which is separate from the main Cloudflare account dashboard. From your Cloudflare account, look for the Zero Trust section in the left navigation. The first time you visit, you'll create a Zero Trust organization name. This becomes part of your team's login URL, so pick something that reflects your organization.

Once inside Zero Trust, the left sidebar gives you access to the full platform: Networks, Access, Gateway, and more. For this walkthrough, you're working under Access.

Creating an Application in the UI

Navigate to Access > Applications and click Add an application. The dashboard presents three application types immediately, and choosing the right one matters.

Close-up of a laptop screen showing a web dashboard interface
The Access application creation flow starts with selecting the application type before any other configuration.

After selecting your application type, you'll define the application domain. This is the URL you want Access to protect. You'll enter the subdomain and select the domain from a dropdown of domains already in your Cloudflare account. For path-based protection, you can append a path like /admin to scope the application to only that portion of your site.

Session duration is configured at the application level. Options range from 30 minutes to 1 month. Shorter sessions are appropriate for sensitive internal tools. Longer sessions reduce friction for tools your team uses all day. A staging environment might warrant a 4-hour session. An internal Grafana dashboard used by on-call engineers might warrant 24 hours.

3
application types in Cloudflare Access: Self-hosted, SaaS, and Non-HTTP

The difference between protecting a full domain and protecting a path deserves a moment. If you set the application domain to yourdomain.com/admin, Access only intercepts requests to that path. The rest of yourdomain.com remains public. This is useful when you have a public-facing site and a single admin section that needs protection, and you don't want to force your public visitors through an identity check.

Choosing the Right Application Type

Self-hosted is the type you'll use most often. It covers any application you host yourself, whether behind a Tunnel or at a public IP. Dashboards, admin panels, internal tools, anything you control.

SaaS applications are third-party services that support SAML or OIDC. You're configuring Access as an identity broker, passing authentication through to the SaaS provider. This is the right choice for tools like Atlassian, Salesforce, or any enterprise SaaS that accepts external identity providers.

Non-HTTP covers SSH and VNC connections. Access can protect SSH sessions through a browser-based terminal without requiring the user to have a configured SSH key on their local machine. This is particularly useful for giving contractors temporary, audited access to a server without handing them credentials.

Connecting Identity Providers: Google, Microsoft, GitHub, and More

Adding an Identity Provider in Zero Trust

Access doesn't authenticate users itself. It delegates that work to an identity provider (IdP), which is the system that actually verifies who someone is. Google, Microsoft, GitHub, Okta, and others all support the OAuth 2.0 or SAML protocols that Access expects. You configure the IdP once in Zero Trust, and then any Access application can use it.

Navigate to Settings > Authentication in the Zero Trust dashboard. This is where all your identity providers live. Click Add new to begin.

Illuminated keyboard and monitor showing login interface
Identity provider configuration lives in Zero Trust Settings, not in the Access application itself. One IdP setup covers all your applications.

Google Workspace Setup

Google is the most common starting point for teams already using Google Workspace. The setup requires creating an OAuth 2.0 application in the Google Cloud Console. You'll go to APIs and Services, create credentials, select OAuth client ID, and choose Web Application as the type.

The critical field is the Authorized redirect URI. Cloudflare provides this value during the IdP setup flow in Zero Trust. It follows the format https://yourteam.cloudflareaccess.com/cdn-cgi/access/callback. Copy it exactly from the Zero Trust dashboard and paste it into Google Cloud Console. After saving, Google gives you a client ID and client secret. Paste both back into the Zero Trust IdP configuration and save.

One OAuth app in Google Cloud. One configuration in Zero Trust. Every Access application you create can use it from that point forward.

GitHub and Microsoft Options

GitHub OAuth is a practical choice for developer teams. Create an OAuth App under your GitHub organization settings, set the callback URL the same way you did for Google, and paste the client ID and secret into Zero Trust. GitHub authentication gives you access to group-level rules based on GitHub organization membership, which is useful for scoping access to internal developer tools by team.

Microsoft Azure Active Directory setup follows a similar pattern but involves registering an application in the Azure portal, configuring API permissions, and handling tenant IDs alongside the client credentials. For enterprise teams already standardized on Microsoft 365, Azure AD is the right call because it gives you group-based policies tied to your existing directory.

One-Time PIN as a Fallback

OTP Requires No IdP Configuration

One-Time PIN authentication is built into Access and requires zero setup. A user enters their email address, Access sends a six-digit code to that address, and the user enters the code to authenticate. There's no OAuth app to create, no client secret to manage. It works immediately. This makes it the right fallback for contractors, external collaborators, or anyone who doesn't have a corporate Google or Microsoft account.

Multiple identity providers can be active simultaneously. When a user hits an Access login page, they see a button for each enabled IdP. They choose the one that applies to them. A full-time employee logs in with Google. A contractor authenticates via OTP. Both land on the same protected application, and your policy rules control what each of them can access.

Writing Login Policies That Actually Enforce Access

Allow, Block, and Bypass Rules

A policy without careful rule design is just theater. Access gives you three actions for any policy: Allow, Block, and Bypass.

Allow does what it sounds like. Users who match the rule criteria get through. Block explicitly denies access and shows the user a block page. Bypass is the one that trips people up. A Bypass rule skips the Access check entirely for matching users or traffic. It's useful for health check endpoints, monitoring agents, or specific IP ranges that need to reach your app without going through the login flow. Use it deliberately, because a misconfigured Bypass rule can open a gap you didn't intend.

Dark screen with code and access control interface elements
Policy rules are evaluated top to bottom. The first matching rule wins, which makes ordering critical when Allow and Block rules coexist.

Building Rules With Identity Attributes

Each policy rule is built from selectors. A selector is an attribute of the user or request that Access can evaluate. Common selectors include:

Emails matches a specific list of email addresses. Email domain matches anyone authenticated with an email ending in a given domain, like @yourcompany.com. Identity provider groups match group membership from your IdP, which is the right approach for teams using Azure AD or Okta with defined groups. Country restricts access based on the user's IP geolocation. IP ranges allow or block specific CIDR blocks. Device posture checks whether the user's device meets requirements you've defined, like having a specific certificate installed or running an approved OS version.

Within a single rule, multiple selectors use AND logic. The user must match all of them. Across multiple rules within a policy, Access uses OR logic. Matching any rule is sufficient to satisfy the policy.

12+
rule selectors available in Cloudflare Access policies, from email to device posture

A practical example: you want to allow your company team and a specific contractor. Create two Include rules inside a single Allow policy. First rule: Email domain is yourcompany.com. Second rule: Emails includes [email protected]. Any user matching either rule gets access.

Policy Ordering and Evaluation Logic

Policies are evaluated top to bottom. First match wins. If your Block rule sits below your Allow rule, the Block never fires for the users who already matched the Allow.

This matters most when you're mixing Allow and Block rules in the same application. A common pattern is to Block specific countries or IP ranges at the top of the policy stack, then Allow your team below that. The Block fires first for matching traffic. Everything else falls through to the Allow evaluation.

A staging environment is a good concrete example. You want your engineering team in and a QA contractor in, but nobody else. One Allow policy. Two Include rules: email domain yourcompany.com and email [email protected]. Session duration set to 4 hours. No other rules. Anyone who doesn't match either rule hits the Access block page without ever touching your staging server.

Real-World Example: Protecting Three Common Internal Apps

Example 1. Locking Down /admin on a Public Site

The scenario: you have a public marketing site at yourdomain.com and a WordPress or custom admin panel at yourdomain.com/admin. The rest of the site is public. You only want employees to reach /admin.

Application type: Self-hosted. Application domain: yourdomain.com/admin. Identity provider: Google. Policy action: Allow. Include rule: Email domain is yourcompany.com. Session duration: 8 hours.

The path-scoped application means public visitors browsing yourdomain.com never encounter the Access login page. Only requests to /admin trigger the identity check. Your origin server doesn't need to change. No firewall rules, no .htaccess modifications. Access handles the gate at the edge.

"The origin doesn't know the gate exists. It just stops receiving unauthenticated requests."

Server rack with organized cabling in a clean data center environment
All three examples share one architectural truth: the origin server has no public exposure for the protected resource.

Example 2. Gating a Staging Environment

The scenario: you have a staging subdomain at staging.yourdomain.com that your engineering team and a QA contractor both need to access. You don't want search engines indexing it, and you definitely don't want clients stumbling onto it before a feature is ready.

Application type: Self-hosted. Application domain: staging.yourdomain.com. Identity providers: Google (for the team) and OTP (for the

Service Authentication: Machine-to-Machine Access

Humans log in through browsers. Scripts don't. That gap creates a real problem the moment you enable Access on an endpoint that your CI/CD pipeline also needs to reach.

What Is Service Auth?

Service authentication is how non-human clients prove their identity to Cloudflare Access. A GitHub Actions workflow, a monitoring agent, a cron job hitting an internal API: none of these can complete an OAuth redirect, click through an identity provider, or handle a session cookie the way a browser does. Without a solution, enabling Access on a protected endpoint breaks every automated system that depends on it.

The solution is a Service Token: a client ID and client secret pair that Access accepts in request headers instead of a browser session. The token bypasses the identity provider flow entirely and maps to a policy rule that explicitly allows it.

Creating a Service Token

Navigate to Zero Trust → Access → Service Auth → Service Tokens and click Create Service Token. Give it a descriptive name tied to the system using it, something like github-actions-deploy or uptime-monitor-prod. Cloudflare generates a CF-Access-Client-Id and a CF-Access-Client-Secret. Copy both immediately. The secret is shown exactly once.

Back in your Access application, open the policy and add a new Allow rule. Set the selector to Service Token, then select the token you just created. Save the policy. That token now has a defined, auditable path into the protected application.

Using the Token in API Calls or CI/CD Pipelines

Pass both values as request headers on every call:

CF-Access-Client-Id: your-client-id-here
CF-Access-Client-Secret: your-client-secret-here

In a GitHub Actions workflow, store both values as encrypted repository secrets and reference them in your workflow YAML. The request hits Cloudflare, the headers are validated against the policy, and the call goes through without any browser interaction required.

Rotate on a Schedule

Service tokens don't expire automatically unless you set a duration at creation. Treat them like passwords. Rotate them on a defined schedule, quarterly at minimum, and immediately if a repository or secret store is compromised.

100%
of automated clients need service tokens once Access is enabled on any endpoint they call

Session Duration and Re-Authentication Controls

Not every application deserves the same session length. A read-only internal wiki and a payment admin panel are not the same risk surface, and Access lets you treat them differently.

Setting Session Length at the App Level

Each Access application has its own session duration setting, found under the application's configuration. Available options run from 30 minutes up through 1 hour, 8 hours, 24 hours, 1 week, 1 month, and no expiry. When a session expires, Cloudflare redirects the user back to the identity provider automatically. There's no custom code required and no error page to configure.

A practical split: set /admin to 1 hour and your internal documentation site to 8 hours. The admin panel gets checked frequently enough that short sessions aren't disruptive. The wiki gets used all day, so forcing hourly logins creates friction with no meaningful security gain.

Global Session vs. Application Session

There are two session layers at work. The global Zero Trust session is set at the organization level and governs how long a user's identity is trusted across all Access applications. The per-application session is shorter and more specific. When the application session expires, the user may be silently re-authenticated using the still-valid global session without seeing a login page. When the global session expires, a full IdP login is required.

The session duration you set is a statement about how much you trust that a valid cookie at hour seven still belongs to the same person who logged in at hour one.

Forcing Re-Auth for Sensitive Apps

For high-sensitivity applications, short sessions are the right default. Payment dashboards, infrastructure consoles, and anything touching production credentials should sit at 30 minutes to 1 hour. The inconvenience is real but proportionate.


Audit Logs and Visibility Into Who Accessed What

Access without logging is just a door with no record of who walked through it. Cloudflare keeps that record.

Finding Access Logs in the Zero Trust Dashboard

Navigate to Zero Trust → Logs → Access. Every authentication event appears here: allowed logins, blocked attempts, and policy evaluations. The log view is searchable and filterable by application name, user email, or date range. If someone on your team reports they can't reach an internal app, this is the first place to look.

What Each Log Entry Tells You

Each entry surfaces a consistent set of fields. Timestamp tells you exactly when the event occurred. User email identifies who authenticated. Identity provider shows which IdP handled the login. Application names the specific Access application involved. Action records whether the request was allowed or blocked. IP address and country add network context that matters for anomaly detection.

That combination is enough to answer most incident questions. Who accessed the staging API at 2 AM? Was it from an expected location? Did the policy block anyone attempting to reach the admin panel this week? The log answers all of it without requiring a separate tool.

Trillions
of requests processed by Cloudflare per month, giving Access log data planetary-scale infrastructure context

Exporting Logs for SIEM or Compliance

Logpush is Cloudflare's mechanism for streaming Access logs to external destinations. Supported targets include S3-compatible storage, Datadog, Splunk, and other SIEM platforms. Once configured, every Access event ships automatically without manual exports.

The compliance use case is straightforward. Regulations and audit requirements frequently demand proof of who accessed a sensitive system and when. Access logs plus Logpush give you a timestamped, identity-linked record that satisfies that requirement without building custom logging infrastructure around your internal applications.

Server room with organized cable management and rack-mounted equipment
Every authentication event logged by Access ties a real identity to a specific application, timestamp, and network location.

Common Mistakes and How to Avoid Them

Access is straightforward to configure and easy to misconfigure. These are the mistakes that show up most often, and each one has a clean fix.

Leaving the Origin Publicly Reachable

This is the most dangerous mistake on the list. If your application server is reachable by direct IP address, Access can be bypassed entirely. Cloudflare sits in front of your origin, but if someone finds the IP and connects directly, they skip the identity check completely.

The fix is to use Cloudflare Tunnel to route traffic, which means the origin never needs a public port open at all. If Tunnel isn't an option, configure your firewall to accept connections only from Cloudflare's published IP ranges and drop everything else.

Hard Rule

If your origin has a publicly routable IP and no firewall rule restricting inbound traffic to Cloudflare ranges, your Access policy is decorative. Fix the network layer first.

Overly Permissive Policies

A policy that allows any user authenticated with Google does not mean any user on your team. It means any of the billions of people with a Google account. That's not a security policy. That's an open door with an extra click.

Scoping a rule to "authenticated via Google" without an email domain restriction is not access control. It's a false sense of access control.

Always scope Allow rules to a specific email domain using the Emails ending in selector, or list individual addresses explicitly for smaller teams. Test the policy before announcing it.

Forgetting Service Auth for Automated Clients

Enabling Access on an endpoint without creating service tokens for every automated client that calls it will break those clients immediately. Monitoring agents stop reporting. Deployment pipelines fail. The fix is to inventory all non-human consumers of a protected endpoint before enabling Access, create tokens for each one, and verify the headers are passing correctly in a staging environment first.


Your Cloudflare Access Setup Checklist

Everything covered in this article compresses into a repeatable sequence. Work through this list for every internal application you bring under Access protection.

Cloudflare Access Setup Checklist 0/9

What's Next: Building on Access With Device Posture and App Launcher

Identity is one gate. The device carrying that identity is another. Access lets you check both.

Device Posture Checks as an Additional Layer

Device posture adds a hardware and software check to the authentication flow. Before granting access, Cloudflare can verify whether the connecting device is enrolled in your organization's management system, running a minimum OS version, or has endpoint security software active. These checks run as additional selectors inside any Access policy. An employee with valid credentials on a personal unmanaged laptop can be blocked while the same employee on a managed corporate device is allowed through.

Posture checks require the WARP client running on the device, which is where Part 11 goes next. WARP is the agent that reports device state back to Cloudflare's network. Without it, posture rules have nothing to evaluate.

The App Launcher Portal for Your Team

The App Launcher is a Cloudflare-hosted portal page that shows each authenticated user every Access-protected application they're permitted to reach. Enable it under Zero Trust → Settings → Authentication → App Launcher. You can set a custom subdomain, something like apps.yourdomain.com, and control which applications appear in the launcher for which users.

For teams moving away from a VPN, the App Launcher replaces the "connect to VPN, then navigate to the internal tool" workflow with a single authenticated portal. Users see only what they're allowed to see.

Zero
open inbound firewall ports required when Access plus Tunnel replaces a traditional VPN setup

The core architecture is now clear. Access is the identity gate. Tunnel is the private pipe connecting your origin to Cloudflare's network without exposing it to the internet. Together they handle what a VPN used to handle, without the overhead of managing VPN infrastructure, certificates, or client configurations at scale. Part 11 goes deeper into device posture enforcement and WARP client integration, which is where this architecture gets its teeth for organizations with managed device fleets.

How was this article?

Share

Link copied to clipboard!

You Might Also Like

Lee Foropoulos

Lee Foropoulos

Business Development Lead at Lookatmedia, fractional executive, and founder of gotHABITS.

🔔

Never Miss a Post

Get notified when new articles are published. No email required.

You will see a banner on the site when a new post is published, plus a browser notification if you allow it.

Browser notifications only. No spam, no email.

0 / 0