Authentication and Permissions

**Referenced Files in This Document** - [worker.js](file://worker.js) - [wrangler.jsonc](file://wrangler.jsonc) - [package.json](file://package.json) - [README.md](file://README.md) - [src/admin/config.yml](file://src/admin/config.yml) - [tina/config.ts](file://tina/config.ts) - [src/alliance-login.njk](file://src/alliance-login.njk) - [src/alliance-members.njk](file://src/alliance-members.njk) - [src/alliance-knowledge.njk](file://src/alliance-knowledge.njk) - [src/_includes/layouts/iaa-base.njk](file://src/_includes/layouts/iaa-base.njk) - [src/_data/allianceMembers.json](file://src/_data/allianceMembers.json) - [cloudflare-pages.toml](file://cloudflare-pages.toml) - [netlify.toml](file://netlify.toml)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendices

Introduction

This document explains the authentication and permission management for the Ace Strategies Prime platform with a focus on:

  • GitHub OAuth integration for CMS access control
  • The authentication flow from GitHub login to CMS access
  • User role management and permission levels
  • The relationship between CMS authentication and member portal access
  • Security considerations including token management and session handling
  • Setup instructions for GitHub OAuth application configuration
  • Troubleshooting authentication issues and access problems
  • Integration between CMS users and member authentication systems

Project Structure

The platform is a static site generated by Eleventy and served via Cloudflare Workers. Authentication and permissions are enforced by the Worker:

  • Member portal authentication (magic link) and CMS OAuth are handled in the Worker
  • The CMS is Sveltia CMS integrated at /admin/ with a Git-backed schema
  • Member portal pages are protected and gated behind session cookies
graph TB
subgraph "Static Site (Eleventy)"
E["_site (built)"]
end
subgraph "Cloudflare Worker"
W["worker.js"]
KV1["KV: MEMBER_EMAILS"]
KV2["KV: MAGIC_TOKENS"]
end
subgraph "External Services"
GH["GitHub OAuth"]
RS["Resend (Email)"]
end
U["User Browser"] --> |"/alliance/members/*"| W
U --> |"/admin/"| W
W --> |"/api/auth*"| GH
W --> |"/alliance/login/ (POST)"| RS
W --> |"/alliance/verify/"| KV2
W --> |Session check| KV1
W --> |Static assets fallback| E

Diagram sources

  • [worker.js:77-321](file://worker.js#L77-L321)
  • [wrangler.jsonc:17-35](file://wrangler.jsonc#L17-L35)
  • [cloudflare-pages.toml:1-17](file://cloudflare-pages.toml#L1-L17)

Section sources

  • [README.md:1-669](file://README.md#L1-L669)
  • [package.json:1-32](file://package.json#L1-L32)
  • [cloudflare-pages.toml:1-17](file://cloudflare-pages.toml#L1-L17)

Core Components

  • Member portal authentication (magic link)
    • Email submission endpoint validates membership and issues a one-time token stored in KV
    • Verification endpoint exchanges the token for a signed session cookie
    • Session cookie is validated on protected routes
  • CMS authentication (GitHub OAuth)
    • Sveltia CMS uses a hosted OAuth proxy; the Worker exposes legacy endpoints for compatibility
  • CMS schema and permissions
    • The CMS schema defines editable content collections and media locations
    • Access to /admin/ is controlled by Sveltia CMS; the Worker enforces OAuth for that route

Key implementation references:

  • Member authentication routes and logic: [worker.js:77-321](file://worker.js#L77-L321)
  • CMS OAuth endpoints: [worker.js:180-227](file://worker.js#L180-L227)
  • CMS schema (YAML): [src/admin/config.yml:1-774](file://src/admin/config.yml#L1-L774)
  • CMS schema (TypeScript): [tina/config.ts:1-331](file://tina/config.ts#L1-L331)

Section sources

  • [worker.js:77-321](file://worker.js#L77-L321)
  • [src/admin/config.yml:1-774](file://src/admin/config.yml#L1-L774)
  • [tina/config.ts:1-331](file://tina/config.ts#L1-L331)

Architecture Overview

The Worker acts as a router and gatekeeper:

  • Protected member routes require a valid session cookie
  • CMS access uses Sveltia CMS OAuth (hosted proxy)
  • Static assets are served from the built site
sequenceDiagram
participant B as "Browser"
participant W as "Worker"
participant RS as "Resend"
participant KV as "KV Namespaces"
B->>W : "POST /alliance/login/" (email)
W->>KV : "Check MEMBER_EMAILS for approval"
alt Approved
W->>KV : "Store token : <hex> -> email (TTL 900s)"
W->>RS : "Send magic link email"
else Not approved
W-->>B : "Redirect to /alliance/login/?sent=1"
end
B->>W : "GET /alliance/verify/?token=<hex>"
W->>KV : "Fetch token : <hex>"
alt Valid
W->>W : "Create signed session token"
W-->>B : "Set HttpOnly; Secure; SameSite=Lax cookie"
W-->>B : "Redirect to /alliance/members/"
else Expired/Invalid
W-->>B : "Redirect to /alliance/login/?error=expired"
end

Diagram sources

  • [worker.js:94-177](file://worker.js#L94-L177)
  • [wrangler.jsonc:17-35](file://wrangler.jsonc#L17-L35)

Section sources

  • [worker.js:94-177](file://worker.js#L94-L177)
  • [README.md:425-477](file://README.md#L425-L477)

Detailed Component Analysis

Member Portal Authentication (Magic Link)

  • Session cookie name: ace_member_session
  • Session duration: 30 days
  • Magic link TTL: 15 minutes
  • Token storage: KV MAGIC_TOKENS with key pattern token:
  • Approved member storage: KV MEMBER_EMAILS with key pattern member:
  • Cookie flags: HttpOnly, Secure, SameSite=Lax
flowchart TD
Start(["Request to /alliance/members/*"]) --> ReadCookie["Read ace_member_session"]
ReadCookie --> HasCookie{"Cookie present?"}
HasCookie --> |No| RedirectLogin["Redirect to /alliance/login/?next={path}"]
HasCookie --> |Yes| VerifyToken["Verify signature and expiry"]
VerifyToken --> Valid{"Valid?"}
Valid --> |Yes| Serve["Serve requested page"]
Valid --> |No| RedirectLogin

Diagram sources

  • [worker.js:77-91](file://worker.js#L77-L91)
  • [worker.js:39-58](file://worker.js#L39-L58)

Section sources

  • [worker.js:77-91](file://worker.js#L77-L91)
  • [worker.js:39-58](file://worker.js#L39-L58)
  • [README.md:455-464](file://README.md#L455-L464)

GitHub OAuth for CMS Access

  • Sveltia CMS uses a hosted OAuth proxy; the Worker exposes legacy endpoints for compatibility
  • The Worker’s /api/auth and /api/auth/callback endpoints initiate and finalize OAuth with GitHub
  • The CMS schema defines editable content collections and media folders
sequenceDiagram
participant Editor as "CMS Editor"
participant CMS as "Sveltia CMS"
participant W as "Worker"
participant GH as "GitHub"
Editor->>CMS : "Open /admin/"
CMS->>W : "GET /api/auth"
W->>GH : "Redirect to GitHub authorize"
GH-->>W : "Callback with code"
W-->>CMS : "Return access token via postMessage"
CMS-->>Editor : "Load CMS with token"

Diagram sources

  • [worker.js:180-227](file://worker.js#L180-L227)
  • [src/admin/config.yml:1-5](file://src/admin/config.yml#L1-L5)
  • [tina/config.ts:5-21](file://tina/config.ts#L5-L21)

Section sources

  • [worker.js:180-227](file://worker.js#L180-L227)
  • [src/admin/config.yml:1-5](file://src/admin/config.yml#L1-L5)
  • [tina/config.ts:5-21](file://tina/config.ts#L5-L21)
  • [README.md:174-204](file://README.md#L174-L204)

CMS Schema and Permission Levels

  • The CMS schema defines collections for content and data files
  • Media upload location is configured under the CMS schema
  • Access to /admin/ is governed by Sveltia CMS; the Worker enforces OAuth for that route
classDiagram
class CMSConfig_YAML {
+collections[]
+media_folder
+public_folder
}
class CMSConfig_TS {
+clientId
+branch
+token
+build.outputFolder
+media.tina.mediaRoot
+schema.collections[]
}
CMSConfig_YAML <.. CMSConfig_TS : "aligned fields"

Diagram sources

  • [src/admin/config.yml:1-774](file://src/admin/config.yml#L1-L774)
  • [tina/config.ts:1-331](file://tina/config.ts#L1-L331)

Section sources

  • [src/admin/config.yml:1-774](file://src/admin/config.yml#L1-L774)
  • [tina/config.ts:1-331](file://tina/config.ts#L1-L331)

Member Portal Pages and Protected Routes

  • Protected pages include the members dashboard and knowledge base index
  • Layouts and content templates define the presentation and navigation

Section sources

  • [src/alliance-members.njk:1-58](file://src/alliance-members.njk#L1-L58)
  • [src/alliance-knowledge.njk:1-96](file://src/alliance-knowledge.njk#L1-L96)
  • [src/_includes/layouts/iaa-base.njk:1-99](file://src/_includes/layouts/iaa-base.njk#L1-L99)
  • [src/_data/allianceMembers.json:1-40](file://src/_data/allianceMembers.json#L1-L40)

Dependency Analysis

  • Worker depends on:
    • KV namespaces MEMBER_EMAILS and MAGIC_TOKENS for membership and tokens
    • Resend API key for sending magic link emails
    • GitHub OAuth client credentials for legacy CMS OAuth endpoints
  • CMS depends on:
    • Sveltia CMS hosted OAuth proxy for authentication
    • GitHub repository for content storage
graph LR
W["worker.js"] --> |Read/Write| KV1["MEMBER_EMAILS"]
W --> |Read/Write| KV2["MAGIC_TOKENS"]
W --> |POST| RS["Resend API"]
W --> |OAuth| GH["GitHub"]
CMS["Sveltia CMS"] --> |OAuth| W

Diagram sources

  • [worker.js:77-321](file://worker.js#L77-L321)
  • [wrangler.jsonc:17-35](file://wrangler.jsonc#L17-L35)

Section sources

  • [worker.js:77-321](file://worker.js#L77-L321)
  • [wrangler.jsonc:17-35](file://wrangler.jsonc#L17-L35)

Performance Considerations

  • Static assets are served directly from the built site via the Worker
  • KV reads/writes for membership and tokens are minimal and fast
  • Email delivery is asynchronous via Resend
  • Consider caching for frequently accessed pages and reducing KV round-trips where feasible

[No sources needed since this section provides general guidance]

Troubleshooting Guide

Common issues and resolutions:

  • Member authentication
    • Session cookie not set or expired: Ensure the cookie flags are accepted by the browser and the domain matches
    • Magic link expired: Links are single-use and expire after 15 minutes
    • Email not received: Confirm Resend API key is set and the email address is approved
  • CMS access
    • GitHub OAuth failing: Verify the legacy endpoints are reachable and CORS preflight is handled
    • Sveltia CMS login issues: Confirm the hosted OAuth proxy is accessible and the callback URL is correct
  • KV configuration
    • KV namespaces missing: Create MEMBER_EMAILS and MAGIC_TOKENS namespaces and bind them in the Worker configuration
  • Environment variables
    • Missing secrets: Ensure SESSION_SECRET, RESEND_API_KEY, and other required secrets are set

Section sources

  • [worker.js:77-321](file://worker.js#L77-L321)
  • [wrangler.jsonc:17-35](file://wrangler.jsonc#L17-L35)
  • [README.md:497-521](file://README.md#L497-L521)
  • [README.md:523-548](file://README.md#L523-L548)

Conclusion

The Ace Strategies Prime platform enforces robust authentication and permissions:

  • Member portal access is secured via magic link emails and signed session cookies
  • CMS access leverages Sveltia CMS with a hosted OAuth proxy, while legacy endpoints remain for compatibility
  • KV namespaces and secrets are central to both member authentication and CMS OAuth
  • The architecture balances simplicity, security, and maintainability

[No sources needed since this section summarizes without analyzing specific files]

Appendices

Setup Instructions: GitHub OAuth Application Configuration

  • Configure Sveltia CMS OAuth proxy (hosted)
    • Use the hosted OAuth proxy URL and callback as documented
  • Legacy endpoints (if used)
    • Set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET in the Worker secrets
    • Ensure /api/auth and /api/auth/callback are reachable and handle CORS preflight

Section sources

  • [README.md:174-204](file://README.md#L174-L204)
  • [worker.js:180-227](file://worker.js#L180-L227)
  • [wrangler.jsonc:28-34](file://wrangler.jsonc#L28-L34)

Setup Instructions: Member Authentication

  • Create KV namespaces
    • MEMBER_EMAILS: stores approved member emails
    • MAGIC_TOKENS: stores one-time tokens with TTL
  • Set secrets
    • SESSION_SECRET: random 32+ bytes for HMAC signing
    • RESEND_API_KEY: for sending magic link emails
  • Manage members
    • Add/remove approved emails using KV key patterns member:

Section sources

  • [wrangler.jsonc:17-35](file://wrangler.jsonc#L17-L35)
  • [README.md:465-477](file://README.md#L465-L477)
  • [README.md:523-548](file://README.md#L523-L548)

Security Considerations

  • Token management
    • Magic link tokens are single-use and short-lived (15 minutes)
    • Session tokens are signed with HMAC-SHA256 and include an expiry
  • Session handling
    • HttpOnly, Secure, SameSite=Lax flags protect against common attacks
    • Session duration is 30 days
  • CORS and CSRF
    • Legacy OAuth endpoints handle CORS preflight
    • Use SameSite=Lax and Secure flags for cookies
  • Secrets and KV
    • Store secrets via Wrangler; avoid committing to the repository
    • Restrict KV keys to the required patterns

Section sources

  • [worker.js:180-227](file://worker.js#L180-L227)
  • [worker.js:39-58](file://worker.js#L39-L58)
  • [worker.js:12-14](file://worker.js#L12-L14)
  • [netlify.toml:14-26](file://netlify.toml#L14-L26)