Account And Downloads
Use this guide when adding customer account pages.
The ⓐ copied account Astro template files cover:
- magic-link access;
- account overview;
- orders and protected invoice links;
- subscriptions;
- licenses;
- downloads;
- account export and delete request examples.
Account pages are host-owned Astro pages that call createMika(Astro, { api }). They should not project raw provider invoice URLs or raw storage paths to the browser. Use Mika-issued hrefs and token-bound routes.
Before exposing account pages in production, the host needs a session/customer policy, magic-link or stronger auth delivery, account rate limits, and storage for tokens, entitlements, licenses, downloads, export requests, and delete requests. Mika supplies the operation contracts and copied page examples; it does not decide who is allowed to see an account.
Account Page
Section titled “Account Page”Treat AUTH_REQUIRED as “not signed in”, not as an error, and redirect first when the billing portal action returns a URL:
---import { createMika } from "@bnomei/emdash-mika/astro";import { actions } from "astro:actions";import { api } from "../lib/mika-api";export const prerender = false;
const Mika = createMika(Astro, { api });const portal = Astro.getActionResult(actions.mika.account.portal);if (portal?.data?.redirectUrl) return Astro.redirect(portal.data.redirectUrl);
const result = await Mika.account.get();const account = result.ok ? result.data : null;const signInRequired = !result.ok && result.error.code === "AUTH_REQUIRED";---account.get() returns orders, subscriptions, entitlements, and downloads in one AccountDTO. Export and delete are forms posting account.export and account.delete — use bracket access for the reserved words: actions.mika.account["export"] and actions.mika.account["delete"].
Magic-Link Sign In
Section titled “Magic-Link Sign In”Mika supplies passwordless magic-link request and verify actions. The host still owns session policy, link delivery, account gating, and any stronger authentication requirements. Request a link with magicLink.request (field email):
<form action={actions.mika.magicLink.request.queryString} method="post"> <input name="email" type="email" required /> <button type="submit">Email me a link</button></form>The emailed link lands on a host page (e.g. /account/magic-link?token=...) that posts magicLink.verify (field token) and redirects to the account on success.
Downloads
Section titled “Downloads”Downloads are tokenized. The package template provides a host-owned .astro interstitial page at templates/astro/pages/download/[token].astro that renders a GET confirmation page and consumes with download.confirm on POST. The seeded template repo uses the same .astro interstitial shape for its fixture download route.
A host can instead write a custom API route that resolves the token to a redirect. Never expose raw storage paths:
import { createMika } from "@bnomei/emdash-mika/astro";import type { APIRoute } from "astro";import { api } from "../../lib/mika-api";export const prerender = false;
export const GET: APIRoute = async ({ params, request, url, redirect }) => { const Mika = createMika({ request, url }, { api }); // a minimal { request, url } context, not full Astro const result = await Mika.download.resolve(params.token!); if (!result.ok) return new Response(result.error.message, { status: result.status }); if (result.data.redirectUrl) return redirect(result.data.redirectUrl); return new Response("Download unavailable.", { status: 404 });};The built-in backend may return only DownloadResolutionDTO.downloadRef. That value is opaque fulfillment evidence, not a URL or storage path. Production host code must map it to an authorized, short-lived HTTPS asset URL and return that as redirectUrl; the copied interstitial fails closed when no URL has been resolved. Keep the signed asset expiry at or before the Mika token expiry, and resolve the asset before consuming the one-time token so a signing failure does not burn the buyer’s link.
Account screens link download.href (tokenized) and order.invoiceHref (behind Mika’s protected order.invoice route) — never raw provider invoice URLs. Licenses show only a key suffix, never the full key.
Raw license-key generation and delivery are also host-owned. Mika can persist a license id and display suffix, but the full secret should travel through the host’s secure issuance and notification boundary rather than Mika DTOs or account pages.
Account Export Downloads
Section titled “Account Export Downloads”Account export download uses a read-before-consume pattern. account.export
returns an AccountExportDTO with a tokenized downloadHref when the export is
ready. The protected route operation account.exportDownload (GET account/export/download) validates the export id and token without consuming
the token, then returns requiresConfirmation: true and confirmMethod: "POST".
The paired account.exportDownloadConsume operation (POST account/export/download) calls the same API with consumeToken: true and
returns the artifact href only after confirmation.
This mirrors the regular download interstitial: GET can render a confirmation
screen, while POST consumes a one-time token. Used or revoked export tokens
return Mika token errors such as TOKEN_USED or DOWNLOAD_REVOKED.
Template Fixture Route
Section titled “Template Fixture Route”The ⓣ seeded GitHub template repo documents /download/download_panel_pack_mira as a smoke-test path only. It is available when the sibling emdash-mika-template app is running with its fixture seed data.
That route is browser-reachable because src/pages/download/[token].astro is a seeded-repo host page. In the seeded repo fixture, download_panel_pack_mira is a literal seeded token for “Mira Panel Pack Download”; after POST confirmation it redirects to a local placeholder file under /template-downloads/.
Do not model production tokens after that readable fixture name. Production download resolution should use Mika-issued opaque tokens, expiry, token consumption, paid-order checks, and entitlement or license revocation checks before redirecting to a signed asset URL. The mira suffix is just the demo product/customer naming used by the seeded repo fixtures.
Verify
Section titled “Verify”- Account pages treat
AUTH_REQUIREDas a sign-in state. - Download links use Mika tokenized hrefs, not raw storage paths.
- Opaque
downloadRefvalues are resolved server-side to short-lived HTTPS URLs before token consumption. - Invoice links stay behind protected order/invoice resolution.
- Raw license keys are generated and delivered by a host-owned secure channel; Mika stores only safe evidence and suffixes.
- Production download tokens are opaque, expiring, and checked against paid-order or entitlement state.
Next: Backend And Provider covers the trusted API behind these account flows. Security And Idempotency covers the host policy boundary.
Source Anchors
Section titled “Source Anchors”- ⓐ
../emdash-mika/src/templates/astro/pages/account.astro - ⓐ
../emdash-mika/src/templates/astro/pages/account/orders.astro - ⓐ
../emdash-mika/src/templates/astro/pages/account/magic-link.astro - ⓐ
../emdash-mika/src/templates/astro/components/AccountSignInPanel.astro - ⓐ
../emdash-mika/src/templates/astro/components/MagicLinkForm.astro - ⓐ
../emdash-mika/src/templates/astro/pages/download/[token].astro - ⓟ
../emdash-mika/src/api/operations.ts - ⓟ
../emdash-mika/src/api/types.ts - ⓟ
../emdash-mika/src/api/backend.ts - ⓟ
../emdash-mika/test/fixtures/digital-delivery.ts - ⓣ
../emdash-mika-template/src/pages/download/[token].astro - ⓣ
../emdash-mika-template/src/lib/mika-fixture-storefront.ts - ⓣ
../emdash-mika-template/seed/mika-actions.seed.json