From fa12df8ec6ef5b387c0dd960c4fed6f8528950c4 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sat, 25 Apr 2026 09:28:02 +0200 Subject: [PATCH] chore(auth): redirect sign-in/sign-up to app.cameleer.io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both auth flows now navigate to the app domain rather than the auth.cameleer.io subdomain: PUBLIC_AUTH_SIGNIN_URL → https://app.cameleer.io/sign-in PUBLIC_AUTH_SIGNUP_URL → https://app.cameleer.io/sign-in?first_screen=register Updated: - .env.example (the canonical reference values) - OPERATOR-CHECKLIST.md (deploy-time secret values) - src/config/auth.test.ts (test fixtures) - src/middleware.ts (CSP-comment about navigation target) - src/pages/privacy.astro (visitor-facing external-links section in §6 of the privacy policy) The auth.ts validator stays strict-https — the new URLs are still absolute https URLs, just on a different host. Logto itself may still run at auth.cameleer.io as the OIDC backend; only the visitor-facing /sign-in entry point moved. Co-Authored-By: Claude Opus 4.7 (1M context) --- .env.example | 4 ++-- OPERATOR-CHECKLIST.md | 4 ++-- src/config/auth.test.ts | 28 ++++++++++++++-------------- src/middleware.ts | 2 +- src/pages/privacy.astro | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.env.example b/.env.example index 536a932..3a369af 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # Logto auth endpoints — the marketing site only performs navigations to these. # No tokens, no cookies, no XHR — these are plain hyperlinks. -PUBLIC_AUTH_SIGNIN_URL=https://auth.cameleer.io/sign-in -PUBLIC_AUTH_SIGNUP_URL=https://auth.cameleer.io/sign-in?first_screen=register +PUBLIC_AUTH_SIGNIN_URL=https://app.cameleer.io/sign-in +PUBLIC_AUTH_SIGNUP_URL=https://app.cameleer.io/sign-in?first_screen=register PUBLIC_SALES_EMAIL=sales@cameleer.io diff --git a/OPERATOR-CHECKLIST.md b/OPERATOR-CHECKLIST.md index 1405529..cadb4ce 100644 --- a/OPERATOR-CHECKLIST.md +++ b/OPERATOR-CHECKLIST.md @@ -75,8 +75,8 @@ Add these under Repository settings → Actions → Secrets (or variables): | `SFTP_PATH` | secret | Absolute path to the Apache vhost docroot configured in konsoleH (typically `/usr/www/users//public_html`). Mismatch → 404 on origin. | | `SFTP_KEY` | secret | Contents of `~/.ssh/cameleer-website-deploy` (private key, PEM) | | `SFTP_KNOWN_HOSTS` | secret | Contents of `hetzner-known-hosts.txt` (captured via `ssh-keyscan`) | -| `PUBLIC_AUTH_SIGNIN_URL` | secret | `https://auth.cameleer.io/sign-in` | -| `PUBLIC_AUTH_SIGNUP_URL` | secret | `https://auth.cameleer.io/sign-in?first_screen=register` | +| `PUBLIC_AUTH_SIGNIN_URL` | secret | `https://app.cameleer.io/sign-in` | +| `PUBLIC_AUTH_SIGNUP_URL` | secret | `https://app.cameleer.io/sign-in?first_screen=register` | | `PUBLIC_SALES_EMAIL` | secret | `sales@cameleer.io` (or whatever sales alias you set up) | These three are not actually secret (they end up in the built HTML), but Gitea's diff --git a/src/config/auth.test.ts b/src/config/auth.test.ts index a21716e..9f22ca0 100644 --- a/src/config/auth.test.ts +++ b/src/config/auth.test.ts @@ -4,57 +4,57 @@ import { resolveAuthConfig } from './auth'; describe('resolveAuthConfig', () => { it('returns both URLs and sales email from env', () => { const cfg = resolveAuthConfig({ - PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in', - PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register', + PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in', + PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register', PUBLIC_SALES_EMAIL: 'sales@cameleer.io', }); - expect(cfg.signInUrl).toBe('https://auth.cameleer.io/sign-in'); - expect(cfg.signUpUrl).toBe('https://auth.cameleer.io/sign-in?first_screen=register'); + expect(cfg.signInUrl).toBe('https://app.cameleer.io/sign-in'); + expect(cfg.signUpUrl).toBe('https://app.cameleer.io/sign-in?first_screen=register'); expect(cfg.salesEmail).toBe('sales@cameleer.io'); }); it('throws if PUBLIC_AUTH_SIGNIN_URL is missing', () => { expect(() => resolveAuthConfig({ - PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register', + PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register', PUBLIC_SALES_EMAIL: 'sales@cameleer.io', })).toThrow(/PUBLIC_AUTH_SIGNIN_URL/); }); it('throws if a URL is not https', () => { expect(() => resolveAuthConfig({ - PUBLIC_AUTH_SIGNIN_URL: 'http://auth.cameleer.io/sign-in', - PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register', + PUBLIC_AUTH_SIGNIN_URL: 'http://app.cameleer.io/sign-in', + PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register', PUBLIC_SALES_EMAIL: 'sales@cameleer.io', })).toThrow(/must be https/); }); it('throws if sales email is not a valid mailto target', () => { expect(() => resolveAuthConfig({ - PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in', - PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register', + PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in', + PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register', PUBLIC_SALES_EMAIL: 'not-an-email', })).toThrow(/PUBLIC_SALES_EMAIL/); }); it('throws if PUBLIC_AUTH_SIGNUP_URL is missing', () => { expect(() => resolveAuthConfig({ - PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in', + PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in', PUBLIC_SALES_EMAIL: 'sales@cameleer.io', })).toThrow(/PUBLIC_AUTH_SIGNUP_URL/); }); it('throws if PUBLIC_AUTH_SIGNUP_URL is not https', () => { expect(() => resolveAuthConfig({ - PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in', - PUBLIC_AUTH_SIGNUP_URL: 'http://auth.cameleer.io/sign-in?first_screen=register', + PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in', + PUBLIC_AUTH_SIGNUP_URL: 'http://app.cameleer.io/sign-in?first_screen=register', PUBLIC_SALES_EMAIL: 'sales@cameleer.io', })).toThrow(/must be https/); }); it('exposes signUpUrl distinct from signInUrl', () => { const cfg = resolveAuthConfig({ - PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in', - PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register', + PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in', + PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register', PUBLIC_SALES_EMAIL: 'sales@cameleer.io', }); expect(cfg.signUpUrl).not.toBe(cfg.signInUrl); diff --git a/src/middleware.ts b/src/middleware.ts index daad692..7ca1928 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -20,7 +20,7 @@ export function buildSecurityHeaders(): Record { "connect-src 'self'", "frame-ancestors 'none'", "base-uri 'self'", - // No forms on this marketing site today (all auth redirects go to auth.cameleer.io + // No forms on this marketing site today (all auth redirects go to app.cameleer.io // as plain navigations). If a future form is added, relax to 'self' or an allow-list. "form-action 'none'", "object-src 'none'", diff --git a/src/pages/privacy.astro b/src/pages/privacy.astro index 3ebe84c..0867cf2 100644 --- a/src/pages/privacy.astro +++ b/src/pages/privacy.astro @@ -67,7 +67,7 @@ const lastUpdated = '2026-04-24';

6. External links

- Sign-in and sign-up links on this site navigate you to auth.cameleer.io (Logto identity service) and subsequently platform.cameleer.io. Those services have their own privacy policies, which apply from the moment you arrive there. + Sign-in and sign-up links on this site navigate you to app.cameleer.io (the Cameleer app, where authentication is handled by Logto). That service has its own privacy policy, which applies from the moment you arrive there.