<div class="wp-block-smartcloud-ai-kit-feature"></div>

Architecture · Deep dive · Protected static

Secure Static WordPress with CloudFront Signed Cookies

A deep dive into protecting static WordPress paths with Cognito identity, Gatey login and CloudFront signed cookies without reintroducing a PHP runtime.

Architecture thesis: Static export removes WordPress from the public request path, but private content still needs a real authorization boundary. The secure pattern is to let Cognito prove identity, let a signer issue time-limited CloudFront cookies, and let CloudFront enforce access to selected static paths.

Static export changes the problem, it does not remove it

Static WordPress is often presented as a security and performance shortcut: export the site, serve it from S3 and CloudFront, and remove PHP from the public request path. That is true for public content, but protected content introduces a new problem.

Once the page is static, WordPress can no longer decide at render time whether a visitor may see it. Authorization has to move to the delivery layer, the API layer or both. For private static pages, the most natural enforcement point is CloudFront.

The Static Site Guardian pattern protects selected paths with CloudFront signed cookies, while Cognito and Gatey handle identity. Static Publisher can still publish the site; the protection layer decides who can retrieve the private objects.

System boundary

Public WordPress source site
        │
        ▼
Static Publisher export
        │
        ▼
S3 bucket with static HTML/assets
        │
        ▼
CloudFront distribution
   ├─ public behaviors: serve directly
   └─ protected behaviors: require signed cookies
        │
        ├─ missing/expired cookie → sign-in route
        │
        ▼
Gatey + Cognito authentication
        │
        ▼
Cookie issuer / signer service
   API Gateway + Lambda or same-domain edge signer
        │
        ▼
CloudFront signed cookies
        │
        ▼
Protected static path is served from S3 through CloudFront

The signed cookie is not the user identity. Cognito proves identity; the signer converts an accepted identity state into a time-limited CloudFront access grant for selected path patterns. CloudFront enforces the grant before the private object is read from S3.

What the secure static stack provisions

Resource / capabilityPurposeSecurity boundaryDesign note
S3 originStores exported static WordPress filesObjects should not be public when CloudFront is the delivery boundaryStatic Publisher can publish files; the protection stack controls access path.
CloudFront distributionServes public and protected paths at the edgeProtected behaviors require signed cookiesThe protected path list is an architectural parameter, not a theme setting.
CloudFront key group / public keyLets CloudFront validate signed-cookie policy signaturesOnly CloudFront sees the public key; the private key stays in the signer sideKey rotation needs a runbook.
Signer serviceIssues signed cookies after identity checksPrivate key in KMS/SSM or equivalent protected storageCan be API Gateway + Lambda or same-domain edge logic depending on cookie scoping needs.
Cognito/Gatey integrationAuthenticates the visitor before cookies are issuedIdentity tokens remain separate from CloudFront cookiesThe login page can be part of the static site.
Route/DNS/certificate optionsMap the public site and optional API/signer domainTLS and hostnames define cookie behaviorDomain strategy matters as much as Lambda code.
WAF / rate controlsReduce abuse of public and signer routesEdge-level filtering before runtime executionEspecially useful when protected paths and signer endpoints are public-facing.

Canonical protected-page flow

1. Visitor requests /members/report.html
        │
        ▼
2. CloudFront matches /members/* protected behavior
        │
        ├─ no valid signed cookie
        ▼
3. Visitor is redirected to /signin/ or a configured sign-in page
        │
        ▼
4. Gatey authenticates the visitor with Cognito
        │
        ▼
5. Signer validates the identity/token/session expectations
        │
        ▼
6. Signer returns CloudFront signed cookies
        │
        ▼
7. Browser retries /members/report.html with cookies
        │
        ▼
8. CloudFront validates policy/signature/key pair and serves S3 object

The flow is intentionally split. Cognito does not directly unlock S3. WordPress does not render a private page on demand. CloudFront does not become an identity provider. Each service performs one part of the boundary.

Signed cookies versus JWTs

A signed cookie and a JWT solve different problems. Confusing them leads to brittle protected-static implementations.

ArtifactIssued byValidated byBest used for
Cognito ID/access tokenAmazon Cognito after authenticationFrontend code, API Gateway authorizer, backend LambdaProving who the user is and what identity-related scopes or claims they have.
IAM credentialsCognito Identity Pool / STSAWS service authorizationCalling IAM-authorized APIs or services from a browser with temporary scoped credentials.
CloudFront signed cookieA trusted signer that owns the private keyCloudFront at the edgeAllowing or denying retrieval of static objects under selected path patterns.
WordPress login cookieWordPress/PHP runtimeWordPressAdmin or traditional dynamic WordPress sessions, not static edge authorization.

A strong protected-static design keeps these layers separate. Use Cognito tokens to decide whether a user may receive a CloudFront cookie. Use CloudFront signed cookies to decide whether an object may be served. Do not try to make one artifact do every job.

The most interesting part of this architecture is not the happy path. It is the domain and cookie-scoping problem that appears when the signer lives on a different subdomain from the static site.

If api.example.com issues the cookie and the protected site is www.example.com, the signer may need a Domain=.example.com cookie so the browser sends it to the site. That works for one site, but it can become messy when multiple protected sites, environments or key pairs live under the same parent domain.

The cleaner pattern is same-domain issuance: the request that sets the CloudFront signed cookies should happen under the same host that serves the protected content. That allows host-only cookies and reduces accidental cross-subdomain leakage.

Domain cookie

Wider reach

Useful when a signer subdomain must set cookies for another host, but it can leak across sibling subdomains and collide in multi-site setups.

Host-only cookie

Narrower boundary

Issued without a Domain attribute, so the browser only sends it to the exact host that created it.

Architecture lesson

DNS names, CloudFront behaviors and signer placement are part of the security model, not deployment details.

Path protection model

Protected static WordPress should be path-driven and explicit. The stack should make it clear which routes are public, which routes require signed cookies, and which API routes require JWT or IAM authorization.

Path classExampleEnforcementCommon mistake
Public content/, /about/, /blog/, assetsCloudFront cache and S3 origin access controlAccidentally placing private JSON, uploads or generated files under public prefixes.
Protected static content/members/*, /training/*, /client/*CloudFront signed cookies on matching behaviors/path patternsOnly hiding links while leaving static objects directly fetchable.
Sign-in and account pages/signin/, /profile/Gatey + Cognito browser flowTreating the login page itself as server-side WordPress state.
Protected APIs/api/* or configured API Gateway domainCognito authorizer, JWT scopes or IAMAssuming a CloudFront cookie proves authorization for API mutations.
AI or workflow endpoints/frontend/prompt, /forms/submitEndpoint-specific auth, WAF, reCAPTCHA and rate limitsReusing page-access logic for higher-risk runtime actions.

Cache and invalidation behavior

Protected static content still benefits from CloudFront caching, but the cache model must respect the signed-cookie boundary. The object can be cached at the edge; the decision to serve it depends on the viewer’s cookie policy and signature.

Static object cache

Cache the file, not the authorization decision

CloudFront can cache the protected object from S3, while still requiring each viewer request to present valid signed cookies.

Cookie TTL

Short enough to limit exposure

Signed cookies should expire according to the sensitivity of the protected area. Long TTLs improve UX but increase risk after account changes.

Invalidation

Content and access are separate

Publishing a changed protected page requires content invalidation. Revoking access may require shorter cookie TTLs or key/policy rotation depending on urgency.

Preview/staging

Use separate hosts and keys

Do not share signer keys or broad parent-domain cookies across dev, staging and production unless that is explicitly intended.

Operational runbook

  1. Define protected paths before export and keep them stable enough to map to CloudFront behaviors or signed-cookie policies.
  2. Deploy the static delivery and protection stack, including CloudFront, signer, key material storage and DNS/certificate settings.
  3. Configure Gatey/Cognito sign-in pages and post-login redirects so authenticated visitors can reach the cookie issuer.
  4. Publish the site with Static Publisher to the configured S3/CloudFront target.
  5. Test public paths, protected paths without cookies, protected paths after login, expired-cookie behavior and direct S3 access.
  6. Document key rotation, cookie TTLs, CloudFront invalidation, signer logs, WAF rules and emergency access revocation.

Failure modes that matter

Failure modeSymptomLikely causeFix direction
Protected route loops to sign-inUser logs in but keeps returning to sign-inCookie domain/path mismatch, signer not setting all required CloudFront cookies or browser rejecting attributesInspect Set-Cookie headers, host-only/domain settings and SameSite/Secure attributes.
Protected file is publicPrivate URL opens in incognito without loginS3 object public, CloudFront behavior not protected or direct origin URL exposedLock S3 public access, enforce CloudFront origin access and verify behavior path patterns.
403 after valid loginUser receives AccessDenied from CloudFrontExpired cookie, wrong key pair ID, invalid signature or policy path mismatchCheck cookie TTL, key group, signer private key and CloudFront policy resource pattern.
Works on one subdomain, fails on anotherCookies are not sent or wrong cookies are sentDomain cookie vs host-only cookie mismatch or collision across sitesMove toward same-domain issuance or isolate environments with distinct hosts and keys.
API succeeds without page access or vice versaUser can call API but not view static page, or view page but cannot call APISeparate auth layers configured differentlyTreat static access and API authorization as separate policies and document both.

When this is a good fit

  • A static WordPress site needs member-only, client-only, training, documentation or portal sections.
  • You want public pages to stay CDN-fast while private pages are enforced at CloudFront rather than PHP.
  • You already use Cognito/Gatey for identity and need that identity to unlock static content.
  • You need a repeatable agency pattern for protected static sites in client-owned AWS accounts.
  • You want a security model that is stronger than hidden links, noindex, frontend-only visibility or JavaScript gating.

When not to use this

  • The private content changes per user at render time and cannot be represented as shared static objects plus API calls.
  • The team cannot operate CloudFront, keys, DNS, certificates and cookie/debugging workflows.
  • The site only needs simple WordPress role-based page protection and is not being statically exported.
  • The project requires immediate per-user revocation without designing short TTLs, key rotation or API-backed checks.

Deep dive

WordPress on AWS Reference Architecture

pillar architecture showing how protected static delivery fits the wider platform

Deep dive

Cognito Day‑2 Identity Architecture

identity backbone for login, groups, scopes and API authorization

Product

Static Publisher

publish rendered WordPress output to S3 and CloudFront

Product

Gatey

Cognito login and account UI that still works after static export

Solution

Secure Static WordPress

solution page for protected static sites and private sections

Guide

Static WordPress Authentication with AWS SAR

deployment-oriented guide for the SAR/static protection pattern

FAQ

Are CloudFront signed cookies the same as Cognito tokens?

No. Cognito tokens prove identity and can authorize APIs. CloudFront signed cookies allow CloudFront to serve protected static objects that match the cookie policy.

Can this protect a static WordPress page after export?

Yes, if the protected page is served through a CloudFront behavior or policy that requires valid signed cookies and the S3 origin is not publicly accessible outside CloudFront.

Does hiding the menu item protect the page?

No. Hiding links improves UX but does not protect the object. A protected static URL must be enforced at CloudFront or another delivery boundary.

Why is same-domain cookie issuance important?

Host-only cookies reduce cross-subdomain leakage and collision risk. If a signer subdomain issues domain-wide cookies, multiple sites or environments under the same parent domain can interfere with each other.

What role does Static Publisher play?

Static Publisher exports and publishes the WordPress-rendered site. It does not decide who can access private objects; that is the job of the CloudFront/signing architecture.

Can APIs use the same CloudFront cookie?

Do not rely on page-access cookies for API authorization. Protected APIs should use Cognito authorizers, JWT scopes, IAM or another API-appropriate authorization layer.

Protect private pages without bringing PHP back

Use this architecture when selected static WordPress paths must be private, but the public site should still be delivered from S3 and CloudFront.