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.
Creating an Application
Section titled “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, }, },});Protecting Cloudflare Workers
Section titled “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" }] }, ],});Device-enrollment (warp)
Section titled “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],});Self-hosted with Google IdP
Section titled “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],});