docs(internet-identity): explain how to serve an app at more than one origin - #339
Conversation
… origin The skill's only substantive mention of derivationOrigin and ii-alternative-origins was Pitfall 8, telling the reader not to use them (correctly, for the icp0.io vs ic0.app case). An agent adding a custom domain to an II app therefore found a prohibition and no recipe, while custom-domains Pitfall 9 already pointed here for one. Adds the positive case: pick the canister address as the derivation origin, set derivationOrigin on the alternative origin only, and serve .well-known/ii-alternative-origins from the derivation origin's canister. On the @dfinity/static-site recipe the official docs' instructions do not work: they prescribe .ic-assets.json5, which is the legacy asset canister's config and is not read or even uploaded by static-site. The file also has no extension, so it needs a _headers entry to serve as application/json with CORS. Both are covered. Pitfall 8 now scopes itself to the icp0.io/ic0.app case it is about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Skill Validation ReportValidating skill: /home/runner/work/icskills/icskills/skills/internet-identityStructure
Frontmatter
Tokens
Markdown
Tokens
Content Analysis
Contamination Analysis
Result: 2 warnings Project Checks |
…list II's validateDerivationOrigin remapToLegacyDomain canonicalizes all three official gateway domains (ic0.app, icp0.io, icp.net) to one form, so a canister served at any of them yields the same principal. Pitfall 8 listed only icp0.io/ic0.app, omitting icp.net — which is now the default domain for new frontend canisters and the one this skill uses as its canonical example (and as the derivation origin in the new section).
|
Pushed a small follow-up commit (8342435) folding one more fix into Pitfall 8 while we were in there. What: Pitfall 8 listed only
and Why it belongs in this PR: The new section itself is unaffected/correct — using
|
# Motivation Pitfall 9 described the symptom — II principals depend on the origin, so a custom domain changes them — and pointed at `internet-identity` for the fix. It left out the part that decides whether the fix is still available: it has to happen before the domain collects sign-ins. Once accounts exist under the new domain, repointing it orphans them. That ordering is what the engine console now warns about on the add-domain form (dfinity/control-panel#3394). # Changes - Rewrote Pitfall 9 to lead with the case that makes it expensive, an app that already has users. - Named the canister address as the origin to pin, so the reader does not have to pick. - Added the ordering constraint and that it cannot be undone. - Dropped the "switching from a canister URL to a custom domain" framing — nothing is switched, the canister address stays reachable, which is why it is the right derivation origin. - Added one eval case. <details> <summary>Eval 9 — Adversarial: custom domain on an app that already has II users (WITH 4/4 | WITHOUT 2/4)</summary> ``` ━━━ Adversarial: custom domain on an app that already has II users ━━━ WITH skill: 4/4 passed ✅ Warns that II principals are per-origin, so existing users would get brand-new accounts at the custom domain ✅ Says to pin the canister address as the derivation origin and list the custom domain in .well-known/ii-alternative-origins BEFORE the domain goes live ✅ Notes that a domain which has already collected sign-ins cannot be repointed without orphaning those accounts ✅ Does NOT present the custom domain switch as principal-neutral or a pure DNS change WITHOUT skill: 2/4 passed ✅ Warns that II principals are per-origin, so existing users would get brand-new accounts at the custom domain ❌ Says to pin the canister address as the derivation origin and list the custom domain in .well-known/ii-alternative-origins BEFORE the domain goes live → The output mentions setting up ii-alternative-origins before switching but never mentions configuring derivationOrigin in the app's login call to pin the canister address, which is the other required half of the mechanism. ❌ Notes that a domain which has already collected sign-ins cannot be repointed without orphaning those accounts → The output only advises keeping the old canister URL live alongside the new domain; it never states the general principle that a domain with existing sign-ins can't be repointed elsewhere without orphaning those accounts. ✅ Does NOT present the custom domain switch as principal-neutral or a pure DNS change ``` The baseline knows principals are per-origin but gives half the fix — `ii-alternative-origins` without `derivationOrigin` — which on its own does nothing. </details> --- Prev. #339 Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…eploy (#340) # Motivation The engine console now shows an app's canister address and names it as the origin an Internet Identity app should derive from (dfinity/control-panel#3394, dfinity/control-panel#3398). The console can only tell the user — the canisters are the user's to write, so the agent deploying them is the one that has to act. And it cannot be fixed later: a domain that has already collected sign-ins cannot be repointed at a derivation origin without orphaning every account made under it. # Changes - Added a subsection to Step 2 saying to pin the derivation origin on the first deploy, before the app has users. - Pointed at the canister that **serves the frontend** as the one whose address to use, built from its canister id. - Called out that `__META_BASE_URL` is not the answer. It is allowed to hold a custom domain, and a custom domain is the one value that must never become the derivation origin. - Demoted `__META_MAIN_CANISTER` to the usual case rather than the rule. It is a console display flag and does not promise the canister serves HTTP. - Noted the Caffeine exception: Caffeine owns those apps' addresses, so the address is not the app's to derive from. - Added Pitfall 18 and one eval case. Left the mechanics in `internet-identity` and linked to it. <details> <summary>Eval 17 — Adversarial: II derivation origin when __META_BASE_URL is a custom domain (WITH 3/3 | WITHOUT 1/3)</summary> ``` ━━━ Adversarial: II derivation origin when __META_BASE_URL is a custom domain ━━━ WITH skill: 3/3 passed ✅ Gives the frontend canister address https://abcde-aaaaa-aaaaa-aaaaa-cai.icp.net as the derivation origin ✅ Explicitly does NOT use the custom domain https://app.example.com as the derivation origin, even though __META_BASE_URL is set to it ✅ Says to set it on the first deploy, before the app has users, because it cannot be applied retroactively without orphaning existing accounts WITHOUT skill: 1/3 passed ❌ Gives the frontend canister address https://abcde-aaaaa-aaaaa-aaaaa-cai.icp.net as the derivation origin → The output gives https://abcde-aaaaa-aaaaa-aaaaa-cai.icp0.io instead of the expected icp.net domain. ✅ Explicitly does NOT use the custom domain https://app.example.com as the derivation origin, even though __META_BASE_URL is set to it ❌ Says to set it on the first deploy, before the app has users, because it cannot be applied retroactively without orphaning existing accounts → The output only warns that login fails if the alternative-origins file is missing, but never states that derivationOrigin must be set before any users exist or that changing it later orphans existing accounts. ``` The case does **not** isolate the `__META_BASE_URL` correction. I ran it against the pre-fix text and that scores 3/3 too, because the rest of the section says the canister address "survives adding, changing, or dropping a custom domain", so an agent reads past the bad clause instead of following it literally. Treat this as a regression guard for the corrected guidance, not as evidence for the correction. The correction stands on the text having been self-contradictory. I dropped a fourth behavior I had drafted ("lists the custom domain as an alternative origin") because it tests the `.well-known` mechanics this skill deliberately delegates to `internet-identity`. </details> --- Prev. #339 --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Motivation
The skill only mentioned
derivationOriginandii-alternative-originsin Pitfall 8, to say don't use them. That is right for theicp0.iovsic0.appcase it covers, but it was the whole coverage, so an agent adding a custom domain to an II app found a prohibition and no recipe.custom-domainsPitfall 9 already pointed here for one. The engine console started surfacing this in dfinity/control-panel#3394 and dfinity/control-panel#3398.Changes
derivationOriginon the alternative origin only, and serve.well-known/ii-alternative-originsfrom the derivation origin's canister._headersblock the@dfinity/static-siterecipe needs. The official docs say to use.ic-assets.json5, which is the legacy asset canister's config — static-site does not read or upload it. The file also has no extension, so it will not serve asapplication/jsonwithout a_headersentry, and certified-assets sets no CORS header by default.icp0.io/ic0.appcase and pointed it at the new section.derivationOrigin") because the baseline scored 3/3 on it — it tested common knowledge, not the skill.Eval 14 — Adversarial: alternative origins on the static-site recipe (WITH 3/3 | WITHOUT 2/3)
The baseline writes the JSON file and stops, which leaves it served with the wrong content type and no CORS header.
Next #340, #341