Support full Access cert URLs for TEAM_DOMAIN

This commit is contained in:
Thomas Gauvin
2026-04-16 23:50:39 -04:00
parent 9e6db4da8e
commit 0d8e52ea57
4 changed files with 18 additions and 7 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
# Cloudflare Access (required in production)
# Cloudflare Access (required in production). TEAM_DOMAIN may be the base Access URL or the full /cdn-cgi/access/certs URL.
POLICY_AUD=your-access-policy-audience-tag
TEAM_DOMAIN=https://your-team.cloudflareaccess.com
+1 -1
View File
@@ -25,7 +25,7 @@ Click the button above to deploy to your Cloudflare account. The deploy flow wil
1. **Set up Email Routing** -- In the Cloudflare dashboard, go to your domain > Email Routing and create a catch-all rule that forwards to this Worker
2. **Enable Email Service** -- The worker needs the `send_email` binding to send outbound emails. See [Email Service docs](https://developers.cloudflare.com/email-routing/email-workers/send-email-workers/)
3. **Create a mailbox** -- Visit your deployed app and create a mailbox for any address on your domain (e.g. `hello@example.com`)
4. **Configure Cloudflare Access** -- Enable [one-click Cloudflare Access](https://developers.cloudflare.com/changelog/post/2025-10-03-one-click-access-for-workers/) on your Worker under Settings > Domains & Routes. The modal will show your `POLICY_AUD` and `TEAM_DOMAIN` values. **You must set these are secrets for your Worker.**
4. **Configure Cloudflare Access** -- Enable [one-click Cloudflare Access](https://developers.cloudflare.com/changelog/post/2025-10-03-one-click-access-for-workers/) on your Worker under Settings > Domains & Routes. The modal will show your `POLICY_AUD` and `TEAM_DOMAIN` values. `TEAM_DOMAIN` can be either your Access team URL or the full `.../cdn-cgi/access/certs` URL. **You must set these as secrets for your Worker.**
## Features
+14 -4
View File
@@ -28,6 +28,17 @@ const requestHandler = createRequestHandler(
import.meta.env.MODE,
);
function getAccessUrls(teamDomain: string) {
const certsPath = "/cdn-cgi/access/certs";
const teamUrl = new URL(teamDomain);
const issuer = teamUrl.origin;
const certsUrl = teamUrl.pathname.endsWith(certsPath)
? teamUrl
: new URL(certsPath, issuer);
return { issuer, certsUrl };
}
// Main app that wraps the API and adds React Router fallback
const app = new Hono<{ Bindings: Env }>();
@@ -54,11 +65,10 @@ app.use("*", async (c, next) => {
}
try {
const JWKS = createRemoteJWKSet(
new URL(`${TEAM_DOMAIN}/cdn-cgi/access/certs`),
);
const { issuer, certsUrl } = getAccessUrls(TEAM_DOMAIN);
const JWKS = createRemoteJWKSet(certsUrl);
await jwtVerify(token, JWKS, {
issuer: TEAM_DOMAIN,
issuer,
audience: POLICY_AUD,
});
} catch {
+2 -1
View File
@@ -11,6 +11,7 @@
],
"vars": {
// Production deploys must also define POLICY_AUD and TEAM_DOMAIN.
// TEAM_DOMAIN may be the base Access URL or the full /cdn-cgi/access/certs URL.
// The worker now fails closed outside local development if Access is not configured.
"DOMAINS": "example.com",
"EMAIL_ADDRESSES": []
@@ -67,4 +68,4 @@
]
}
]
}
}