A Cloudflare Access application is the protected resource — a self-hosted domain, a SaaS integration, or a launcher bookmark. Three variants are strictly typed (self_hosted, saas, bookmark); the rest fall back to a permissive shape.
Self-Hosted Application
Section titled “Self-Hosted Application”Protect a hostname with one or more reusable AccessPolicy resources.
import { AccessApplication, AccessPolicy } from "alchemy/cloudflare";
const employees = await AccessPolicy("employees", { name: "Employees", decision: "allow", include: [{ email_domain: { domain: "acme.com" } }],});
const admin = await AccessApplication("admin", { type: "self_hosted", name: "Internal Admin", domain: "admin.acme.com", policies: [employees], sessionDuration: "8h",});
// Validate `cf-access-jwt-assertion` against `admin.aud` at your origin.Bookmark Application
Section titled “Bookmark Application”A vanity link in the Access launcher — no policy enforcement, just a tile.
const wiki = await AccessApplication("wiki", { type: "bookmark", name: "Internal Wiki", domain: "https://wiki.acme.com", appLauncherVisible: true,});SaaS OIDC Integration
Section titled “SaaS OIDC Integration”Cloudflare brokers SSO between your IdP and a SaaS vendor over OIDC (or SAML).
const slack = await AccessApplication("slack-saas", { type: "saas", name: "Slack", saas: { authType: "oidc", redirectUris: ["https://acme.slack.com/oidc/callback"], scopes: ["openid", "email", "profile"], }, policies: [employees],});
// slack.clientId / slack.clientSecret.unencrypted are returned only on// creation — register them in Slack's SSO settings.typeandzoneare immutable — changing either forces replacement.domainis required forself_hosted, and is the link target forbookmark.- For SaaS OIDC apps,
clientSecretis only returned on creation; subsequent updates retain the original. - Set
zone: someZoneto scope the application to a specific zone instead of the account; onlyself_hosted,bookmark, and a few others support this.