apex-surface-auth
The standard pattern for public apex auth: login, signup, forgot-password, and account-deletion on your marketing surface — schema-less, anonymously reachable, without leaking admin nav or internal topology.
A typical app has two mounts sharing locale and primitives:
- Admin UI →
createKumikoApp(loads the full schema after login via the authenticatedGET /api/schema) - Apex →
createPublicSurface(no schema, ever)
What it shows
Section titled “What it shows”- Four public routes —
/login,/signup,/forgot-password,/delete-account(+ confirm) using bundled auth screens. createPublicSurface— stacksclientFeaturesproviders and i18n only, not their gates (anAuthGatewould lock the public surface).AuthShellProvider— auth card inside marketing chrome instead of fullscreen (optional; default fullscreen still works).composeApexAccountApp()— server feature list for all four flows.- Anonymous deletion — email-verified magic-link flow when the user cannot log in (GDPR Art. 17 lockout case).
anonymousAccess— lets unauthenticated/api/writehit anonymous handlers on the apex host tenant.
Client: createPublicSurface + AuthShell
Section titled “Client: createPublicSurface + AuthShell”import { ForgotPasswordScreen, SignupScreen, createLoginRoute, AuthShellProvider, emailPasswordClient,} from "@cosmicdrift/kumiko-bundled-features/auth-email-password/web";import { RequestAccountDeletionScreen, ConfirmAccountDeletionScreen,} from "@cosmicdrift/kumiko-bundled-features/user-data-rights/web";import { createPublicSurface } from "@cosmicdrift/kumiko-renderer/web";
// createLoginRoute, not a raw LoginScreen render — it owns the challenge-// swap for a second factor, so mounting auth-mfa later doesn't need this// route touched again. Pass `mfaVerifyScreen: MfaVerifyScreen` (from// `.../auth-mfa/web`) once the app mounts auth-mfa.const LoginRoute = createLoginRoute({ loginScreenProps: { signupHref: "/signup" } });
createPublicSurface({ clientFeatures: [emailPasswordClient()], // SessionProvider + i18n shell: ({ children }) => ( <MarketingChrome> <AuthShellProvider shell={(card) => <div className="py-12 flex justify-center">{card}</div>}> {children} </AuthShellProvider> </MarketingChrome> ), routes: [ { path: "/login", component: <LoginRoute /> }, { path: "/signup", component: <SignupScreen loginHref="/login" /> }, { path: "/forgot-password", component: <ForgotPasswordScreen loginHref="/login" /> }, { path: "/delete-account", component: <RequestAccountDeletionScreen /> }, { path: "/delete-account/confirm", component: <ConfirmAccountDeletionScreen /> }, ], fallback: <LoginRoute />,});Server: composition + anonymousAccess
Section titled “Server: composition + anonymousAccess”composeApexAccountApp() (see src/feature.ts) mounts features for all four
flows. Login/signup/password reset come from auth-email-password; the
anonymous email-verified deletion flow from user-data-rights:
request-deletion-by-email(anonymous, enumeration-safe) → magic linkconfirm-deletion-by-token(anonymous) → starts grace period
runProdApp({ envSchema, // composeEnvSchema({ core: frameworkCoreEnvSchema, features }) features: composeApexAccountApp({ deletionTokenSecret: process.env.DELETION_TOKEN_SECRET!, deletionVerifyUrl: "https://app.example.com/delete-account/confirm", sendDeletionVerificationEmail: async ({ email, verifyUrl }) => { // Must be non-blocking (enqueue) — synchronous send enables timing oracle. await delivery.notify("account.deletion.verify", { email, verifyUrl }); }, }), anonymousAccess: { defaultTenantId: APEX_TENANT_ID },});Why deletion is anonymous
Section titled “Why deletion is anonymous”GDPR Art. 17 applies when the user cannot log in (lockout). The flow is
email-verified (magic link), not login-gated. The HMAC token carries userId
- expiry (no DB table); purpose
"deletion-request"blocks replay on other token endpoints. Second confirm is idempotent (user_not_in_active_state).
Needs a running Postgres and TEST_DATABASE_URL set (e.g. postgres://postgres:postgres@127.0.0.1:5432/postgres, see demo/.env.example).
bun test src/__tests__/feature.integration.test.tsProves end-to-end over real /api/write without auth:
request-deletion-by-email→ verification email enqueuedconfirm-deletion-by-token→ user statusDeletionRequested- Unknown email → same 200 response, no mail (enumeration-safe)
Related samples
Section titled “Related samples”- user-profile — logged-in self-service profile (password, email, deletion while authenticated).
- session-revocation — wire
createSessionCallbacks()so logout invalidates JWTs server-side.
Source code
Section titled “Source code”The feature entry point — embedded straight from the source file, so the code here is exactly what runs. Multi-file samples keep their remaining files next to it on GitHub (link below):
// apex-surface-auth recipe — the evident way for public apex content.//// A Kumiko app has a public apex presence (landing/login) AND a// schema-driven admin UI. The admin UI mounts via createKumikoApp (full// schema). The apex mounts via createPublicSurface — schema-LESS, anonymously// reachable, no admin nav/topology leak. Both share locale + primitives.//// This recipe shows:// 1. Server: the feature composition for the 4 account flows + the anonymous,// email-verified deletion flow (lockout-safe).// 2. Client (comment below + README): how createPublicSurface + AuthShell// mount the screens in the apex chrome.//// CLIENT-WIRING (the app's apex.tsx — renderer/web, only a reference here, since// recipes pull in no browser deps)://// import {// ForgotPasswordScreen, SignupScreen, createLoginRoute,// AuthShellProvider, emailPasswordClient,// } from "@cosmicdrift/kumiko-bundled-features/auth-email-password/web";// import {// RequestAccountDeletionScreen, ConfirmAccountDeletionScreen,// defaultTranslations as deletionI18n,// } from "@cosmicdrift/kumiko-bundled-features/user-data-rights/web";// import { createPublicSurface } from "@cosmicdrift/kumiko-renderer/web";//// // AuthShell: the auth card renders inside the marketing chrome instead of// // fullscreen. Default (without a provider) stays the fullscreen wrapper.// const shell = ({ children }) => (// <MarketingChrome>// <AuthShellProvider shell={(card) => <div className="py-12 flex justify-center">{card}</div>}>// {children}// </AuthShellProvider>// </MarketingChrome>// );//// // createLoginRoute — do NOT render LoginScreen directly: the route// // needs the challenge-swap logic for a second factor. Without it// // (e.g. a raw <LoginScreen />) an MFA-enrolled user gets stuck at login// // as soon as the app mounts auth-mfa at some point. If the app mounts// // auth-mfa, add `mfaVerifyScreen: MfaVerifyScreen` (from// // "@cosmicdrift/kumiko-bundled-features/auth-mfa/web").// const LoginRoute = createLoginRoute({ loginScreenProps: { signupHref: "/signup" } });//// createPublicSurface({// clientFeatures: [emailPasswordClient()], // bringt SessionProvider + i18n// shell,// routes: [// { path: "/login", component: <LoginRoute /> },// { path: "/signup", component: <SignupScreen loginHref="/login" /> },// { path: "/forgot-password", component: <ForgotPasswordScreen loginHref="/login" /> },// { path: "/delete-account", component: <RequestAccountDeletionScreen /> },// { path: "/delete-account/confirm", component: <ConfirmAccountDeletionScreen /> },// ],// fallback: <LoginRoute />,// });////// SERVER-WIRING: the app enables `anonymousAccess` (defaultTenantId = the// apex host tenant) so /api/write reaches the anonymous deletion handlers://// runProdApp({ features: composeApexAccountApp({...}), envSchema,// anonymousAccess: { defaultTenantId: APEX_TENANT_ID } })
import { createAuthEmailPasswordFeature } from "@cosmicdrift/kumiko-bundled-features/auth-email-password";import { createAuthFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";import { createComplianceProfilesFeature } from "@cosmicdrift/kumiko-bundled-features/compliance-profiles";import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";import { createDataRetentionFeature } from "@cosmicdrift/kumiko-bundled-features/data-retention";import { createPersonalAccessTokensFeature } from "@cosmicdrift/kumiko-bundled-features/personal-access-tokens";import { createSessionsFeature } from "@cosmicdrift/kumiko-bundled-features/sessions";import { createTenantFeature } from "@cosmicdrift/kumiko-bundled-features/tenant";import { createUserFeature } from "@cosmicdrift/kumiko-bundled-features/user";import { createUserDataRightsFeature, type SendDeletionVerificationEmailFn,} from "@cosmicdrift/kumiko-bundled-features/user-data-rights";import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
export type ApexAccountAppOptions = { /** HMAC secret for the deletion verify token. */ readonly deletionTokenSecret: string; /** Apex route of the confirm screen; the handler appends the token as a * URL fragment (`#token=`). */ readonly deletionVerifyUrl: string; /** Sending the verify magic link. MUST be non-blocking (enqueue) — a * synchronous send would open a timing oracle for account enumeration. */ readonly sendDeletionVerificationEmail: SendDeletionVerificationEmailFn;};
// Full feature composition for the public account flows. The// user-data-rights options enable the anonymous deletion flow; the remaining// features provide login/register/PW (auth-email-password) + the// require chain (user-data-rights → data-retention + compliance-profiles +// sessions).export function composeApexAccountApp(opts: ApexAccountAppOptions): FeatureDefinition[] { return [ createConfigFeature(), createUserFeature(), createTenantFeature(), createAuthEmailPasswordFeature(), createDataRetentionFeature(), createComplianceProfilesFeature(), createAuthFoundationFeature(), createPersonalAccessTokensFeature({ scopes: {} }), createSessionsFeature(), createUserDataRightsFeature({ deletionTokenSecret: opts.deletionTokenSecret, deletionVerifyUrl: opts.deletionVerifyUrl, sendDeletionVerificationEmail: opts.sendDeletionVerificationEmail, }), ];}📄 On GitHub: samples/recipes/apex-surface-auth/src/feature.ts