diff --git a/tasks/new/2026-0821.01.jul.story.auth-yes.extract-standalone-repo-1828.md b/tasks/complete/2026-0821.01.jul.story.auth-yes.extract-standalone-repo-1828.md similarity index 100% rename from tasks/new/2026-0821.01.jul.story.auth-yes.extract-standalone-repo-1828.md rename to tasks/complete/2026-0821.01.jul.story.auth-yes.extract-standalone-repo-1828.md diff --git a/tasks/new/2026-0821.01.jul.feat.auth-yes.seamless-3rd-party-sso-1609.md b/tasks/new/2026-0821.01.jul.feat.auth-yes.seamless-3rd-party-sso-1609.md index bb79a5c..ab2efa4 100644 --- a/tasks/new/2026-0821.01.jul.feat.auth-yes.seamless-3rd-party-sso-1609.md +++ b/tasks/new/2026-0821.01.jul.feat.auth-yes.seamless-3rd-party-sso-1609.md @@ -1,46 +1,131 @@ # TASK METADATA -- **Target Files:** `auth-yes/server/db.ts`, `auth-yes/server/oidc.ts`, - `auth-yes/server/main.ts`, `auth-yes/ui/admin/integrations.tsx` (and related - UI files) -- **Core Objective:** Implement seamless 3rd-party SSO via a Zero-Click OIDC - Provider and Traefik ForwardAuth Header injection. -- **Dependencies:** Core Auth-Yes session mechanisms, Valkey cache, Hono - routing, React/JSX for UI. -- **Additional Important Notes:** Ensure OIDC logic is decoupled from `main.ts` - to prevent a monolith. Database migrations are required for OIDC - clients/authorization codes. +- **Target Files:** + - `server/oidc.ts` + - `server/db.ts` + - `server/main.ts` + - `ui/admin/integrations.tsx` + - `server/oidc.test.ts` + - `server/main.test.ts` +- **Core Objective:** Implement a Zero-Click OpenID Connect (OIDC) Identity + Provider in Auth-Yes and enhance Traefik ForwardAuth header injection to + enable seamless, passwordless SSO across 3rd-party self-hosted services (e.g., + Gitea, Grafana, Portainer). +- **Dependencies:** + - PostgreSQL 18 DDL schema for OIDC client applications and authorization + codes + - Valkey 8 token/code replay protection cache + - Existing WebAuthn passkey session cookie authority (`.atyg.org`) +- **Additional Important Notes:** + - Keep `server/oidc.ts` modular and decoupled from `main.ts`. + - Strictly React-free pure Hono SSR JSX for UI components. + - Implement full PKCE (RFC 7636) support and standard OIDC Discovery metadata + at `/.well-known/openid-configuration`. --- -### Phase 2: The Bonus Stage — Seamless 3rd-Party SSO (Gitea, Portainer, etc.) +## Architectural Considerations & Risks -Your vision for frictionless 3rd-party access without double-logins is -achievable through two native patterns we can bring directly into auth-yes: +### Risks -#### 1. The "Zero-Click" OIDC Provider in auth-yes +1. **Open Redirect Vulnerabilities:** Malicious actors could craft authorization + requests redirecting users to arbitrary domains. + - _Mitigation:_ Strict exact-match validation against registered + `redirect_uris` in PostgreSQL. +2. **Authorization Code & Token Replay:** Stolen or intercepted authorization + codes could be exchanged for tokens. + - _Mitigation:_ Single-use authorization codes with short TTL (e.g. 60s) + backed by Valkey atomic deletion on exchange (`GETDEL` / transaction). + Mandatory PKCE (`code_challenge` / `code_verifier`). +3. **Cross-Origin & Wildcard Cookie Collisions:** Subdomain applications + attempting to hijack `.atyg.org` session cookies. + - _Mitigation:_ Explicit `SameSite=Lax`, `Secure`, and `HttpOnly` cookie + constraints with server-side revocation validation. -• Most self-hosted power tools (Gitea, Nextcloud, Grafana, Portainer, Proxmox, -Vaultwarden) support standard OpenID Connect (OIDC). • When auth-yes exposes -standard OIDC endpoints (/oauth/authorize, /oauth/token, /oauth/userinfo): • You -click "Login with Auth-Yes" on Gitea (or configure Gitea for auto-login). • -Gitea redirects to auth.atyg.org. • Because you already have your .atyg.org -passkey cookie active, auth-yes instantly authorizes and redirects back in ~10 -milliseconds without presenting any login dialogs. • Gitea automatically creates -and syncs your account on the fly. +### Alternatives Considered -#### 2. Reverse-Proxy Header Authentication (Traefik ForwardAuth) +- **Heavy OAuth2 Frameworks / Dependencies:** Rejected. Incorporating large + Node.js OAuth libraries introduces runtime dependencies and bloat. A native, + zero-dependency TypeScript implementation utilizing Deno standard Web Crypto + API (`crypto.subtle`) for RS256/EdDSA JWT signing ensures a minimal, + ultra-fast footprint. -• Apps like Gitea have native Reverse Proxy Auth -(ENABLE_REVERSE_PROXY_AUTHENTICATION = true). • When Traefik calls -/api/forward-auth, auth-yes injects X-Forwarded-User: . Gitea -immediately trusts the header and logs you in transparently with zero -interaction. +--- -#### 3. 3rd-Party App Integrations Manager in Admin Console +## Proposed Implementation -• We can expand our Application Registry (/admin/apps) with an Integrations -Catalog (Client IDs, OIDC secrets, callback URLs, and role-mapping presets for -Gitea, Grafana, Portainer, etc.). • This gives you a single pane of glass to -manage passkey-secured SSO across your entire self-hosted ecosystem, allowing -you to optionally bypass Cloudflare Zero Trust popups entirely. +### Phase 1: Database Schema & Client Registry Migration (`server/db.ts`) + +1. Add `oidc_clients` table: + - `client_id` (VARCHAR PK) + - `client_name` (VARCHAR) + - `client_secret_hash` (VARCHAR) + - `redirect_uris` (TEXT[] array of allowed callback URLs) + - `grant_types` (TEXT[] e.g., `["authorization_code", "refresh_token"]`) + - `scopes` (TEXT[] e.g., `["openid", "profile", "email", "roles"]`) + - `created_at` (TIMESTAMP) +2. Add `oidc_authorization_codes` table or Valkey ephemeral storage: + - Ephemeral 60s TTL storage for `code`, `client_id`, `user_id`, + `code_challenge`, and `scopes`. + +--- + +### Phase 2: OIDC Provider & Endpoints (`server/oidc.ts`) + +1. **OIDC Discovery & JWKS:** + - `GET /.well-known/openid-configuration`: Returns standard OIDC discovery + metadata. + - `GET /oauth/jwks.json`: Serves public keys for RS256/Ed25519 token + verification. +2. **Zero-Click Authorization Endpoint (`GET /oauth/authorize`):** + - Validates `client_id`, `redirect_uri`, `response_type=code`, and PKCE + challenge. + - Checks active Auth-Yes session cookie (`auth_session`). + - If session is active: instantly issues authorization `code` and redirects + to `redirect_uri?code=...&state=...` with 0 UI friction. + - If unauthenticated: redirects to WebAuthn passkey login and resumes flow + upon successful authentication. +3. **Token Endpoint (`POST /oauth/token`):** + - Verifies authorization code, PKCE `code_verifier`, and client + authentication. + - Issues signed RS256 `id_token` (JWT) and `access_token`. +4. **UserInfo Endpoint (`GET /oauth/userinfo`):** + - Validates Bearer access token and returns user profile, email, and mapped + roles. + +--- + +### Phase 3: Traefik ForwardAuth Header Enrichment (`server/main.ts`) + +1. Expand `GET /api/forward-auth` to inject standard identity headers for + reverse-proxy auth: + - `X-Forwarded-User: ` + - `X-Forwarded-Email: ` + - `X-Forwarded-Groups: ` + - `X-Forwarded-Preferred-Username: ` +2. This allows Gitea, Grafana, and tools with + `ENABLE_REVERSE_PROXY_AUTHENTICATION = true` to log users in transparently + upon reverse-proxy routing. + +--- + +### Phase 4: Integrations Catalog Admin UI (`ui/admin/integrations.tsx`) + +1. Build pure Hono SSR JSX admin view under `/admin/integrations`: + - Quick-setup presets for popular self-hosted services (Gitea, Grafana, + Portainer, Nextcloud, Vaultwarden). + - Display Client ID, Secret generation, and copyable config snippets for each + application. + +--- + +### Phase 5: Unit & Integration Tests (`server/oidc.test.ts`) + +1. Test OIDC Discovery metadata and JWKS key export. +2. Test `/oauth/authorize` with active passkey session (verifying zero-click + instant redirect). +3. Test `/oauth/token` exchange with valid PKCE verifier vs invalid verifier + (verifying rejection). +4. Test token replay prevention (verifying code cannot be used twice). +5. Verify all quality gates pass (`deno fmt`, `deno task lint`, + `deno task check`, `deno task test`).