While setting up an app-scoped CLI identity with icp identity link web, I hit a failure that turned out to be reproducible for any app, and I wanted to share the root cause plus the workaround I ended up with, and ask whether there is a supported path I overlooked.
Symptom
icp identity link web my-identity --auth https://id.ai --app <app-domain>
The browser opens id.ai/cli and correctly shows the app domain. Clicking Allow access produces Unexpected error / Unauthorized, with the console stack pointing at onAuthorize.
What actually triggers it
The identity had its default account for that origin renamed in the II account list. That is the whole trigger; it is not specific to any app or derivation origin. With an untouched default account the command works first try.
Root cause
The CLI flow always requests the default account: account_number is hardcoded to [] in cli/utils.ts. Renaming a default account materialises it create_default_account allocates a real account number, sets config.default_account_number = Some(n), and overwrites the AccountReference whose account_number was None. But read_account resolves a None request by scanning for a reference whose account_number.is_none(), finds nothing, and returns None, which prepare_account_delegation maps to Unauthorized even though config.default_account_number points at exactly the account being asked for.
The principal is unaffected by the rename (a stored default keeps seed_from_anchor, so the seed is still calculate_anchor_seed(anchor, origin)), so this is purely a lookup-path miss. Filed with code links here: https://github.com/dfinity/internet-identity/issues/4171
Workaround
icp identity delegation request prints an SPKI public key and leaves the identity pending, and the classic #authorize postMessage protocol accepts an externally supplied sessionPublicKey. So the identity can be completed out of band:
icp identity delegation request <name>→ session public key (PEM SPKI).- From a page whose origin is permitted for the target derivation origin, open an
identity.ic0.app/#authorizepopup and post{ kind: "authorize-client", sessionPublicKey, maxTimeToLive, derivationOrigin }. - Serialise the returned chain into the JSON shape
icp identity delegation signemits (hexpublicKey, hexsignature/pubkey, hexexpiration). icp identity delegation use <name> --from-json <file>.
The classic flow still shows the account picker, so the right account gets selected and the resulting principal matches the one the web app derives. I have this wrapped in a script that verifies the resulting principal against the expected one and discards the identity on mismatch.
Questions
- Is there an existing, supported way to do this that I missed? some flag or flow that lets the CLI target a specific II account rather than the default?
- Is an
--accountselector on the CLI flow planned? Bothprepare_account_delegationandget_account_delegationalready take the argument; only the CLI page pins it toNone. - Is the classic
#authorizepostMessage protocol something I can keep depending on, or is it on a deprecation path in favour of the id.ai flows? If it is going away, I would rather not build on it.
Thanks in advance!