Cloudflare.Access reference
Application
Section titled “Application”Source:
src/Cloudflare/Access/Application.ts
A Cloudflare Zero Trust Access application.
Replaces the curl-based POST /accounts/{accountId}/access/apps workflow
with an Alchemy-managed resource. Supports every Cloudflare application
type including warp, which Cloudflare requires for device enrolment via
the WARP client.
Access policies are authored as standalone Policy resources
and referenced here by id — there is no inline-policy support.
Application: Creating an Application
Section titled “Application: Creating an Application”Self-hosted application gated by a reusable Access policy
const allowMyOrg = yield* Cloudflare.Access.Policy("AllowMyOrg", { name: "Allow example.com via Google", decision: "allow", include: [{ emailDomain: { domain: "example.com" } }],});
const app = yield* Cloudflare.Access.Application("InternalDashboard", { type: "self_hosted", domain: "dashboard.example.com", sessionDuration: "24h", policies: [allowMyOrg],});Managed OAuth for an MCP server
const app = yield* Cloudflare.Access.Application("McpServer", { type: "self_hosted", domain: "mcp.example.com", oauthConfiguration: { enabled: true, grant: { sessionDuration: "24h", accessTokenLifetime: "15m", }, dynamicClientRegistration: { enabled: true, allowAnyOnLocalhost: true, allowAnyOnLoopback: true, }, },});Application: Protecting Cloudflare Workers
Section titled “Application: Protecting Cloudflare Workers”Require Access on a specific Worker
// The application owns the policies (inline here — no separate Policy// resource needed); the Worker enrolls itself via its `access` prop,// covering its custom domains, routes, workers.dev URL, and version// preview URLs.const App = Cloudflare.Access.Application("TeamOnly", { type: "self_hosted", policies: [ { decision: "allow", include: [{ emailDomain: "example.com" }] }, ],});
export default class Api extends Cloudflare.Worker<Api>()("Api", { main: import.meta.url, access: { application: App },}, /* ... */) {}Require Access on every Worker in the account
// Covers all current AND future Workers. Hostname-level policies beat// Worker-level policies, which beat this account-level policy — so an// individual Worker can still be opened up with its own application.yield* Cloudflare.Access.Application("ProtectAllWorkers", { type: "self_hosted", destinations: [ Cloudflare.Access.AllWorkers, // production traffic of every Worker Cloudflare.Access.AllWorkerPreviews, // every Worker's preview URLs ], policies: [ { decision: "allow", include: [{ emailDomain: "example.com" }] }, ],});Application: Device-enrollment (warp)
Section titled “Application: Device-enrollment (warp)”// There can only be ONE warp app per account; Cloudflare auto-derives the// domain (`${authDomain}/warp`) so do not pass `domain` for this type.const allowCorp = yield* Cloudflare.Access.Policy("AllowCorpUsers", { name: "Allow corp users", decision: "allow", include: [{ emailDomain: { domain: "example.com" } }],});
const enroll = yield* Cloudflare.Access.Application("warp-login", { type: "warp", allowedIdps: [googleIdpId], autoRedirectToIdentity: true, sessionDuration: "720h", policies: [allowCorp],});Application: Self-hosted with Google IdP
Section titled “Application: Self-hosted with Google IdP”const admins = yield* Cloudflare.Access.Policy("AdminsOnly", { name: "Admins only", decision: "allow", include: [ { gsuite: { email: "admins@example.com", identityProviderId: googleIdpUuid, }, }, ],});
const app = yield* Cloudflare.Access.Application("AdminConsole", { type: "self_hosted", domain: "admin.example.com", allowedIdps: [googleIdpUuid], autoRedirectToIdentity: true, policies: [admins],});Bookmark
Section titled “Bookmark”Source:
src/Cloudflare/Access/Bookmark.ts
A Cloudflare Zero Trust Access bookmark application — an unprotected link shown in the App Launcher.
Bookmark: Creating a Bookmark
Section titled “Bookmark: Creating a Bookmark”Basic bookmark
const bookmark = yield* Cloudflare.Access.Bookmark("Wiki", { domain: "wiki.example.com",});Bookmark with a logo, hidden from the App Launcher
const bookmark = yield* Cloudflare.Access.Bookmark("Wiki", { name: "internal-wiki", domain: "wiki.example.com", logoUrl: "https://example.com/logo.png", appLauncherVisible: false,});Bookmark: Preferred Alternative
Section titled “Bookmark: Preferred Alternative”const app = yield* Cloudflare.Access.Application("Wiki", { type: "bookmark", domain: "wiki.example.com",});Certificate
Section titled “Certificate”Source:
src/Cloudflare/Access/Certificate.ts
A Cloudflare Zero Trust Access mTLS certificate. Uploads a CA certificate that Access uses to validate client certificates presented to protected applications on the associated hostnames.
The certificate body is immutable — changing the PEM replaces the resource. The name and associated hostnames converge in place.
Certificate: Creating a Certificate
Section titled “Certificate: Creating a Certificate”Upload a CA certificate
const ca = yield* Cloudflare.Access.Certificate("ClientCa", { certificate: CA_PEM, // -----BEGIN CERTIFICATE----- ...});Certificate with associated hostnames
const ca = yield* Cloudflare.Access.Certificate("ClientCa", { name: "corp-client-ca", certificate: CA_PEM, associatedHostnames: ["app.example.com"],});Certificate: Updating Hostnames
Section titled “Certificate: Updating Hostnames”const ca = yield* Cloudflare.Access.Certificate("ClientCa", { certificate: CA_PEM, associatedHostnames: ["app.example.com", "admin.example.com"],});CustomPage
Section titled “CustomPage”Source:
src/Cloudflare/Access/CustomPage.ts
A Cloudflare Zero Trust Access custom page. Replaces the default Access
block pages (identity_denied / forbidden) with custom HTML, which can
then be selected on an Access application.
CustomPage: Creating a Custom Page
Section titled “CustomPage: Creating a Custom Page”Custom forbidden page
const page = yield* Cloudflare.Access.CustomPage("Forbidden", { type: "forbidden", customHtml: "<html><body><h1>Access denied</h1></body></html>",});Custom identity-denied page with an explicit name
const page = yield* Cloudflare.Access.CustomPage("Denied", { name: "corp-identity-denied", type: "identity_denied", customHtml: "<html><body><h1>Who are you?</h1></body></html>",});CustomPage: Updating the HTML
Section titled “CustomPage: Updating the HTML”const page = yield* Cloudflare.Access.CustomPage("Forbidden", { type: "forbidden", customHtml: "<html><body><h1>Still denied</h1></body></html>",});GetIdentityProvider
Section titled “GetIdentityProvider”Source:
src/Cloudflare/Access/GetIdentityProvider.ts
Looks up an existing Access identity provider by display name and/or
type, returning its attributes — or undefined when nothing matches.
As a data source, invoke it at plan time via
getIdentityProvider — the result is an Output resolved during
plan/deploy and inert inside deployed bundles. Useful for referencing
IdPs that are managed outside the stack (e.g. the dashboard-provisioned
cloudflare WARP login method, whose display name is often "").
The implementation is registered by Cloudflare.providers().
As a runtime binding inside a Worker, provide
GetIdentityProviderHttp — it mints a scoped
AccountApiToken with the Access: Organizations, Identity Providers, and Groups Read permission and binds it into the Worker so
the lookup can run at runtime.
GetIdentityProvider: Looking Up Identity Providers
Section titled “GetIdentityProvider: Looking Up Identity Providers”Restrict an Access application to the managed WARP IdP
const warpIdp = Cloudflare.Access.getIdentityProvider({ type: "cloudflare",});
yield* Cloudflare.Access.Application("Admin", { domain: "admin.example.com", allowedIdps: [warpIdp.identityProviderId.as<string>()],});Look up an IdP by display name
const okta = Cloudflare.Access.getIdentityProvider({ name: "Okta SSO" });Look up an IdP at runtime inside a Worker
// init — bind the lookupconst findWarpIdp = yield* Cloudflare.Access.GetIdentityProvider({ type: "cloudflare",});
// runtime — resolve the IdPconst warp = yield* findWarpIdp();Source:
src/Cloudflare/Access/Group.ts
A Cloudflare Zero Trust Access group — a reusable, account-scoped set of
Access rule criteria. Groups are referenced from Access policies via a
{ group: { id } } rule, letting many policies share one membership
definition.
Group: Creating a Group
Section titled “Group: Creating a Group”Allow a single email domain
const group = yield* Cloudflare.Access.Group("ExampleDomain", { include: [{ emailDomain: { domain: "example.com" } }],});Combine include, exclude and require rules
const group = yield* Cloudflare.Access.Group("UsEngineers", { include: [{ emailDomain: { domain: "example.com" } }], exclude: [{ email: { email: "intern@example.com" } }], require: [{ geo: { countryCode: "US" } }],});Group: Referencing a Group from a Policy
Section titled “Group: Referencing a Group from a Policy”const group = yield* Cloudflare.Access.Group("Team", { include: [{ emailDomain: { domain: "example.com" } }],});
const policy = yield* Cloudflare.Access.Policy("AllowTeam", { decision: "allow", include: [{ group: { id: group.groupId } }],});IdentityProvider
Section titled “IdentityProvider”Source:
src/Cloudflare/Access/IdentityProvider.ts
A Cloudflare Zero Trust Access identity provider — the login method (one-time PIN, generic OIDC/SAML, or a named provider like GitHub, Google, Okta, or Azure AD) users authenticate with before Access policies evaluate.
Props are a discriminated union on type: each provider type only
accepts (and requires) its own config fields, so a missing
directoryId on an azureAD IdP or a GitHub config on an oidc IdP
is a compile-time error. The type is immutable (config shapes are
disjoint per type — changing it replaces the IdP); name, config, and
SCIM settings converge in place. Cloudflare masks secret config fields
(clientSecret, API tokens) on read, so those fields diff against
your previously declared props instead of observed cloud state.
By default the IdP is created at the account level (the modern Zero
Trust organization scope); pass zoneId to scope it to a single zone
(legacy zone-level Access). Moving between scopes replaces the IdP.
IdentityProvider: Creating an Identity Provider
Section titled “IdentityProvider: Creating an Identity Provider”One-time PIN (no external dependencies)
const otp = yield* Cloudflare.Access.IdentityProvider("Pin", { type: "onetimepin",});Generic OIDC provider
const oidc = yield* Cloudflare.Access.IdentityProvider("Sso", { type: "oidc", config: { clientId: "my-client-id", clientSecret: "my-client-secret", authUrl: "https://idp.example.com/authorize", tokenUrl: "https://idp.example.com/token", certsUrl: "https://idp.example.com/keys", scopes: ["openid", "email", "profile"], },});Microsoft Entra ID (Azure AD)
const entra = yield* Cloudflare.Access.IdentityProvider("Entra", { type: "azureAD", config: { clientId: "my-client-id", clientSecret: "my-client-secret", directoryId: "my-tenant-id", supportGroups: true, },});Zone-scoped IdP (legacy zone-level Access)
const zoneIdp = yield* Cloudflare.Access.IdentityProvider("ZoneSso", { zoneId: zone.zoneId, type: "github", config: { clientId: "my-client-id", clientSecret: "my-client-secret", },});IdentityProvider: Restricting an Application to an IdP
Section titled “IdentityProvider: Restricting an Application to an IdP”yield* Cloudflare.Access.Application("Admin", { domain: "admin.example.com", allowedIdps: [oidc.identityProviderId],});InfrastructureTarget
Section titled “InfrastructureTarget”Source:
src/Cloudflare/Access/InfrastructureTarget.ts
A Cloudflare Access Infrastructure Target — a server (hostname + IPv4/IPv6 address) protected by Access for Infrastructure (SSH).
Targets are referenced by infrastructure Access applications, which attach SSH access policies to them. Hostname and IP are both mutable in place; the target’s identity is its Cloudflare-assigned UUID.
InfrastructureTarget: Creating a Target
Section titled “InfrastructureTarget: Creating a Target”Basic IPv4 target
const target = yield* Cloudflare.Access.InfrastructureTarget("Bastion", { hostname: "bastion.internal", ip: { ipv4: { ipAddr: "10.0.0.5" } },});Target scoped to a virtual network
const vnet = yield* Cloudflare.Tunnel.VirtualNetwork("Staging", {});const target = yield* Cloudflare.Access.InfrastructureTarget("DbHost", { hostname: "db.staging.internal", ip: { ipv4: { ipAddr: "10.4.0.10", virtualNetworkId: vnet.virtualNetworkId, }, },});InfrastructureTarget: Updating
Section titled “InfrastructureTarget: Updating”// Hostname and IP update in place — same targetId, no replacement.const target = yield* Cloudflare.Access.InfrastructureTarget("Bastion", { hostname: "bastion.internal", ip: { ipv4: { ipAddr: "10.0.0.6" } },});KeyConfiguration
Section titled “KeyConfiguration”Source:
src/Cloudflare/Access/KeyConfiguration.ts
The Cloudflare Zero Trust Access service-key rotation configuration for an
account (/accounts/{account_id}/access/keys).
The key configuration is an account singleton — it always exists, so this
resource never creates or deletes anything physical. Reconcile PUTs the
rotation interval when the observed value differs from the desired one;
destroy restores the interval the account had before Alchemy first managed
it (captured as initialKeyRotationIntervalDays).
KeyConfiguration: Managing the rotation interval
Section titled “KeyConfiguration: Managing the rotation interval”Rotate Access service keys every 30 days
const keys = yield* Cloudflare.Access.KeyConfiguration("Keys", { keyRotationIntervalDays: 30,});Inspect rotation status
const keys = yield* Cloudflare.Access.KeyConfiguration("Keys", { keyRotationIntervalDays: 90,});// keys.daysUntilNextRotation, keys.lastKeyRotationAtMcpPortal
Section titled “McpPortal”Source:
src/Cloudflare/Access/McpPortal.ts
A Cloudflare Zero Trust AI Controls MCP portal — a hosted gateway that aggregates MCP servers behind a single Access-protected hostname so administrators can govern which AI tools and prompts are exposed to users.
The product surface is in beta and requires the AI Controls
entitlement; accounts without it receive the typed Forbidden error
on all writes. Attaching servers to the portal is managed out of band
(a future Cloudflare.Access.McpServer resource).
McpPortal: Creating an MCP portal
Section titled “McpPortal: Creating an MCP portal”Minimal portal
const portal = yield* Cloudflare.Access.McpPortal("AiPortal", { hostname: "mcp.example.com",});Portal with gateway egress
const portal = yield* Cloudflare.Access.McpPortal("AiPortal", { hostname: "mcp.example.com", description: "Company-approved AI tools", secureWebGateway: true,});Organization
Section titled “Organization”Source:
src/Cloudflare/Access/Organization.ts
Account-level Cloudflare Zero Trust organization settings — the team domain, login branding, session lifetimes, WARP authentication toggle, etc.
Wraps PUT /accounts/{account_id}/access/organizations.
Organization: Configuring the organization
Section titled “Organization: Configuring the organization”const org = yield* Cloudflare.Access.Organization("Org", { authDomain: "acme.cloudflareaccess.com", name: "Acme", sessionDuration: "24h", allowAuthenticateViaWarp: true, loginDesign: { logoPath: "https://acme.example/logo.png", backgroundColor: "#111111", textColor: "#ffffff", },});Policy
Section titled “Policy”Source:
src/Cloudflare/Access/Policy.ts
A reusable, account-scoped Cloudflare Access policy. Distinct from the
inline policies attached directly to an Application — a reusable
policy can be referenced by multiple applications by id.
Policy: Creating a Policy
Section titled “Policy: Creating a Policy”Allow a single email domain
const policy = yield* Cloudflare.Access.Policy("AllowExampleDomain", { decision: "allow", include: [{ emailDomain: { domain: "example.com" } }],});Allow everyone but require purpose justification
const policy = yield* Cloudflare.Access.Policy("OpenWithJustification", { decision: "allow", include: [{ everyone: {} }], purposeJustificationRequired: true, sessionDuration: "12h",});Policy: Combining rule groups
Section titled “Policy: Combining rule groups”const policy = yield* Cloudflare.Access.Policy("EngineersExceptInterns", { decision: "allow", include: [{ emailDomain: { domain: "example.com" } }], exclude: [{ email: { email: "intern@example.com" } }], require: [{ geo: { countryCode: "US" } }],});ServiceToken
Section titled “ServiceToken”Source:
src/Cloudflare/Access/ServiceToken.ts
A Cloudflare Zero Trust Access service token. Service tokens let
machine-to-machine clients authenticate to Access-protected applications
by sending the CF-Access-Client-ID / CF-Access-Client-Secret headers.
The client secret is only revealed by Cloudflare on create and rotate; the provider stores it redacted in state and carries it forward across reads.
ServiceToken: Creating a Service Token
Section titled “ServiceToken: Creating a Service Token”Basic token with a generated name
const token = yield* Cloudflare.Access.ServiceToken("Ci", {});// token.clientId / token.clientSecret authenticate requestsToken with an explicit name and validity
const token = yield* Cloudflare.Access.ServiceToken("Deploys", { name: "deploy-bot", duration: "17520h", // 2 years});ServiceToken: Rotating the Secret
Section titled “ServiceToken: Rotating the Secret”const token = yield* Cloudflare.Access.ServiceToken("Ci", { clientSecretVersion: 2, // was 1 — bumping rotates the secret});ServiceToken: Authorizing a Token
Section titled “ServiceToken: Authorizing a Token”const token = yield* Cloudflare.Access.ServiceToken("Ci", {});
const policy = yield* Cloudflare.Access.Policy("AllowCi", { decision: "non_identity", include: [{ serviceToken: { tokenId: token.serviceTokenId } }],});Source:
src/Cloudflare/Access/Tag.ts
A Cloudflare Zero Trust Access tag. Tags are plain labels that can be attached to Access applications to group and filter them.
The tag’s name is its identity — there is nothing to update in place, so renaming replaces the tag.
Tag: Creating a Tag
Section titled “Tag: Creating a Tag”Tag with a generated name
const tag = yield* Cloudflare.Access.Tag("Team", {});Tag with an explicit name
const tag = yield* Cloudflare.Access.Tag("Team", { name: "platform-team",});Tag: Tagging an Application
Section titled “Tag: Tagging an Application”const tag = yield* Cloudflare.Access.Tag("Team", { name: "platform-team" });
const app = yield* Cloudflare.Access.Application("Dashboard", { type: "self_hosted", domain: "dash.example.com", tags: [tag.name],});