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.
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.
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.
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.
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
Navigating to Zero Trust Dashboard
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.
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.
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.
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.
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.
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.
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
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."
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-hereIn 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.
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.
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.
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.
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.
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.
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.
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.