diff --git a/hosting/oisy-signer-demo/frontend/package.json b/hosting/oisy-signer-demo/frontend/package.json index b1edad45c5..2592cf49f3 100644 --- a/hosting/oisy-signer-demo/frontend/package.json +++ b/hosting/oisy-signer-demo/frontend/package.json @@ -13,9 +13,9 @@ "format:check": "prettier --check ." }, "dependencies": { - "@icp-sdk/canisters": "~3.5.0", - "@icp-sdk/core": "~5.0.0", - "@icp-sdk/signer": "5.3.0", + "@icp-sdk/canisters": "~4.0.0", + "@icp-sdk/core": "~6.1.0", + "@icp-sdk/signer": "~6.0.0", "class-variance-authority": "~0.7.1", "lucide-react": "~0.575.0", "react": "~19.2.4", diff --git a/motoko/backend_only/icp.yaml b/motoko/backend_only/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/backend_only/icp.yaml +++ b/motoko/backend_only/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/basic_bitcoin/icp.yaml b/motoko/basic_bitcoin/icp.yaml index ddb94934dd..1a11eef52e 100644 --- a/motoko/basic_bitcoin/icp.yaml +++ b/motoko/basic_bitcoin/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" networks: - name: local diff --git a/motoko/canister_factory/icp.yaml b/motoko/canister_factory/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/canister_factory/icp.yaml +++ b/motoko/canister_factory/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/canister_logs/icp.yaml b/motoko/canister_logs/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/canister_logs/icp.yaml +++ b/motoko/canister_logs/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/cert-var/frontend/package.json b/motoko/cert-var/frontend/package.json index d0cc35cdb0..c5f9d65ed9 100644 --- a/motoko/cert-var/frontend/package.json +++ b/motoko/cert-var/frontend/package.json @@ -8,10 +8,10 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.0.0" + "@icp-sdk/core": "~6.1.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "vite": "5.4.11" } } diff --git a/motoko/cert-var/icp.yaml b/motoko/cert-var/icp.yaml index 491bcb0316..f4a871c2ed 100644 --- a/motoko/cert-var/icp.yaml +++ b/motoko/cert-var/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/composite_query/icp.yaml b/motoko/composite_query/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/composite_query/icp.yaml +++ b/motoko/composite_query/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/daily_planner/frontend/package.json b/motoko/daily_planner/frontend/package.json index 859836e9b9..47cd6254aa 100644 --- a/motoko/daily_planner/frontend/package.json +++ b/motoko/daily_planner/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.2.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/motoko/daily_planner/icp.yaml b/motoko/daily_planner/icp.yaml index 491bcb0316..f4a871c2ed 100644 --- a/motoko/daily_planner/icp.yaml +++ b/motoko/daily_planner/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/evm_block_explorer/frontend/package.json b/motoko/evm_block_explorer/frontend/package.json index b3bbed2ca0..61c36672ee 100644 --- a/motoko/evm_block_explorer/frontend/package.json +++ b/motoko/evm_block_explorer/frontend/package.json @@ -8,13 +8,13 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~6.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1", "react-json-view-lite": "2.3.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.4.0", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/motoko/evm_block_explorer/icp.yaml b/motoko/evm_block_explorer/icp.yaml index 15c407ff07..f7041537e0 100644 --- a/motoko/evm_block_explorer/icp.yaml +++ b/motoko/evm_block_explorer/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/filevault/README.md b/motoko/filevault/README.md index b3c0ba4952..ad564444ef 100644 --- a/motoko/filevault/README.md +++ b/motoko/filevault/README.md @@ -34,6 +34,8 @@ bash test.sh icp network stop ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: ```bash diff --git a/motoko/filevault/frontend/package.json b/motoko/filevault/frontend/package.json index accf38438e..ea0451838f 100644 --- a/motoko/filevault/frontend/package.json +++ b/motoko/filevault/frontend/package.json @@ -8,13 +8,13 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "~5.0.0", - "@icp-sdk/core": "~5.2.0", + "@icp-sdk/auth": "~10.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.3.0", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/motoko/filevault/frontend/src/App.jsx b/motoko/filevault/frontend/src/App.jsx index cfa1d585d2..c3320c6575 100644 --- a/motoko/filevault/frontend/src/App.jsx +++ b/motoko/filevault/frontend/src/App.jsx @@ -1,20 +1,21 @@ import React, { useState, useEffect } from 'react'; -import { AuthClient } from '@icp-sdk/auth/client'; -import { createBackendActor, identityProviderUrl } from './actor'; +import { authClient, getBackendActor } from './actor'; import '../index.css'; function App() { - const [isAuthenticated, setIsAuthenticated] = useState(false); - const [authClient, setAuthClient] = useState(); - const [actor, setActor] = useState(); + const [isAuthenticated, setIsAuthenticated] = useState(authClient.isAuthenticated()); const [files, setFiles] = useState([]); const [errorMessage, setErrorMessage] = useState(); const [fileTransferProgress, setFileTransferProgress] = useState(); - useEffect(() => { - updateActor(); - setErrorMessage(); - }, []); + // Sign-out or session expiry, including from another tab. + useEffect( + () => + authClient.subscribe(() => { + if (!authClient.isAuthenticated()) setIsAuthenticated(false); + }), + [] + ); useEffect(() => { if (isAuthenticated) { @@ -22,31 +23,22 @@ function App() { } }, [isAuthenticated]); - async function updateActor() { - const authClient = await AuthClient.create(); - const identity = authClient.getIdentity(); - const actor = createBackendActor(identity); - const isAuthenticated = await authClient.isAuthenticated(); - - setActor(actor); - setAuthClient(authClient); - setIsAuthenticated(isAuthenticated); - } - async function login() { - await authClient.login({ - identityProvider: identityProviderUrl, - onSuccess: updateActor - }); + try { + await authClient.signIn(); + setIsAuthenticated(true); + } catch (error) { + console.error('Sign-in failed:', error); + } } async function logout() { - await authClient.logout(); - updateActor(); + await authClient.signOut(); } async function loadFiles() { try { + const actor = await getBackendActor(); const fileList = await actor.getFiles(); setFiles(fileList); } catch (error) { @@ -64,6 +56,7 @@ function App() { return; } + const actor = await getBackendActor(); if (await actor.checkFileExists(file.name)) { setErrorMessage(`File "${file.name}" already exists. Please choose a different file name.`); return; @@ -111,6 +104,7 @@ function App() { progress: 0 }); try { + const actor = await getBackendActor(); const totalChunks = Number(await actor.getTotalChunks(name)); const fileType = await actor.getFileType(name) ?? ''; let chunks = []; @@ -147,6 +141,7 @@ function App() { async function handleFileDelete(name) { if (window.confirm(`Are you sure you want to delete "${name}"?`)) { try { + const actor = await getBackendActor(); const success = await actor.deleteFile(name); if (success) { await loadFiles(); diff --git a/motoko/filevault/frontend/src/actor.js b/motoko/filevault/frontend/src/actor.js index e35f888b2d..f625439699 100644 --- a/motoko/filevault/frontend/src/actor.js +++ b/motoko/filevault/frontend/src/actor.js @@ -1,3 +1,4 @@ +import { AuthClient } from "@icp-sdk/auth/client"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import { createActor } from "./bindings/backend"; @@ -16,18 +17,38 @@ const agentOptions = { rootKey: canisterEnv?.IC_ROOT_KEY, }; +// Internet Identity is deployed on the local network (`ii: true` in icp.yaml). const isLocal = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.endsWith(".localhost"); -const II_CANISTER_ID = "uqzsh-gqaaa-aaaaq-qaada-cai"; const networkPort = process.env.REPLICA_PORT || window.location.port || "8000"; -export const identityProviderUrl = isLocal - ? `http://${II_CANISTER_ID}.localhost:${networkPort}` - : "https://id.ai"; + +// The client mints its delegations by calling the II canister, so its agent +// needs the network's root key to verify the responses. +export const authClient = new AuthClient({ + identityProvider: { + authorizeUrl: isLocal + ? `http://id.ai.localhost:${networkPort}/authorize` + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, +}); export function createBackendActor(identity) { return createActor(canisterId, { agentOptions: { ...agentOptions, identity }, }); } + +let cached; + +// Resolves the identity at call time and reuses the actor while it is unchanged. +export async function getBackendActor() { + const identity = authClient.isAuthenticated() ? await authClient.getIdentity() : undefined; + if (!cached || cached.identity !== identity) { + cached = { identity, actor: createBackendActor(identity) }; + } + return cached.actor; +} diff --git a/motoko/filevault/icp.yaml b/motoko/filevault/icp.yaml index 3c04c7fd0a..a9678a69fd 100644 --- a/motoko/filevault/icp.yaml +++ b/motoko/filevault/icp.yaml @@ -6,7 +6,7 @@ networks: canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/flying_ninja/frontend/package.json b/motoko/flying_ninja/frontend/package.json index c98614e9c6..47cd6254aa 100644 --- a/motoko/flying_ninja/frontend/package.json +++ b/motoko/flying_ninja/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/motoko/flying_ninja/icp.yaml b/motoko/flying_ninja/icp.yaml index 491bcb0316..f4a871c2ed 100644 --- a/motoko/flying_ninja/icp.yaml +++ b/motoko/flying_ninja/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/hello_cycles/icp.yaml b/motoko/hello_cycles/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/hello_cycles/icp.yaml +++ b/motoko/hello_cycles/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/hello_world/frontend/package.json b/motoko/hello_world/frontend/package.json index d0cc35cdb0..c5f9d65ed9 100644 --- a/motoko/hello_world/frontend/package.json +++ b/motoko/hello_world/frontend/package.json @@ -8,10 +8,10 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.0.0" + "@icp-sdk/core": "~6.1.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "vite": "5.4.11" } } diff --git a/motoko/hello_world/icp.yaml b/motoko/hello_world/icp.yaml index 491bcb0316..f4a871c2ed 100644 --- a/motoko/hello_world/icp.yaml +++ b/motoko/hello_world/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/ic-pos/README.md b/motoko/ic-pos/README.md index 079de02ed7..efdce674b7 100644 --- a/motoko/ic-pos/README.md +++ b/motoko/ic-pos/README.md @@ -46,6 +46,8 @@ icp network start -d bash deploy.sh ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + > **Use `bash deploy.sh`, not `icp deploy`, locally.** The ICRC-1 ledger and index require init args (minting account, initial balances, and the ledger's canister ID) that are only known after identities and canisters are created, so `deploy.sh` installs them with the right arguments. A plain `icp deploy` traps because those canisters receive no init args. `deploy.sh` installs a local ICRC-1 ledger + index (a throwaway token named **LICRC1**, distinct from the mainnet TICRC1), the `backend`, and the `frontend`. Internet Identity is provided by the local network (`ii: true` in `icp.yaml`) at `http://id.ai.localhost:8000` — no separate deployment. Open the frontend URL printed by the script. diff --git a/motoko/ic-pos/frontend/package.json b/motoko/ic-pos/frontend/package.json index 5b5ec7fa57..dfbb8f3658 100644 --- a/motoko/ic-pos/frontend/package.json +++ b/motoko/ic-pos/frontend/package.json @@ -10,9 +10,9 @@ }, "dependencies": { "@hookform/resolvers": "^3.1.1", - "@icp-sdk/auth": "~7.1.0", - "@icp-sdk/canisters": "~3.6.0", - "@icp-sdk/core": "~5.4.0", + "@icp-sdk/auth": "~10.0.0", + "@icp-sdk/canisters": "~4.0.0", + "@icp-sdk/core": "~6.1.0", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", @@ -32,7 +32,7 @@ "zod": "^3.22.3" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.4.0", + "@icp-sdk/bindgen": "~0.4.1", "@tailwindcss/forms": "^0.5.10", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "~4", diff --git a/motoko/ic-pos/frontend/src/lib/auth.tsx b/motoko/ic-pos/frontend/src/lib/auth.tsx index 6b6b5599ed..75db25e8fd 100644 --- a/motoko/ic-pos/frontend/src/lib/auth.tsx +++ b/motoko/ic-pos/frontend/src/lib/auth.tsx @@ -9,7 +9,7 @@ import { } from "react"; import { AuthClient } from "@icp-sdk/auth/client"; import type { Identity } from "@icp-sdk/core/agent"; -import { iiUrl } from "./env"; +import { identityProvider, rootKey } from "./env"; interface AuthContextValue { /** The authenticated identity, or `undefined` when logged out. */ @@ -30,30 +30,35 @@ export function AuthProvider({ children }: { children: ReactNode }) { const [isInitializing, setIsInitializing] = useState(true); useEffect(() => { + // The client mints its delegations by calling the II canister, so its + // agent needs the network's root key to verify the responses. const client = new AuthClient({ - identityProvider: iiUrl, - // Keep the session alive; expiry is handled explicitly via - // useHandleAgentError when the delegation is rejected. - idleOptions: { disableIdle: true }, + identityProvider, + agentOptions: { rootKey }, }); setAuthClient(client); + // Leave the signed-in views when the session ends, including from another tab. + const unsubscribe = client.subscribe(() => { + if (!client.isAuthenticated()) setIdentity(undefined); + }); + void (async () => { - // getIdentity() restores a previous session from storage if present. - await client.getIdentity(); if (client.isAuthenticated()) { setIdentity(await client.getIdentity()); } setIsInitializing(false); })(); + + return () => { + unsubscribe(); + client.dispose(); + }; }, []); const login = useCallback(async () => { if (!authClient) return; - await authClient.signIn(); - if (authClient.isAuthenticated()) { - setIdentity(await authClient.getIdentity()); - } + setIdentity(await authClient.signIn()); }, [authClient]); const clear = useCallback(async () => { diff --git a/motoko/ic-pos/frontend/src/lib/env.ts b/motoko/ic-pos/frontend/src/lib/env.ts index a87c9c92f0..f7668fbbd5 100644 --- a/motoko/ic-pos/frontend/src/lib/env.ts +++ b/motoko/ic-pos/frontend/src/lib/env.ts @@ -39,8 +39,11 @@ export const host = window.location.origin; export const isLocal = /localhost|127\.0\.0\.1/.test(window.location.hostname); // Internet Identity provider. Locally the network serves II at -// id.ai.localhost (icp.yaml `ii: true`); on mainnet it's id.ai. The -// `/authorize` path is required by @icp-sdk/auth. -export const iiUrl = isLocal - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize"; +// id.ai.localhost (icp.yaml `ii: true`); on mainnet it's id.ai. The canister +// that mints delegations has the same ID on both. +export const identityProvider = { + authorizeUrl: isLocal + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", +}; diff --git a/motoko/ic-pos/icp.yaml b/motoko/ic-pos/icp.yaml index c704f3d567..c22ce1317d 100644 --- a/motoko/ic-pos/icp.yaml +++ b/motoko/ic-pos/icp.yaml @@ -23,7 +23,7 @@ canisters: - name: backend init_args: "(0 : nat)" recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/icp_transfer/icp.yaml b/motoko/icp_transfer/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/icp_transfer/icp.yaml +++ b/motoko/icp_transfer/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/icrc2-swap/icp.yaml b/motoko/icrc2-swap/icp.yaml index a295ab4da4..ce09bff934 100644 --- a/motoko/icrc2-swap/icp.yaml +++ b/motoko/icrc2-swap/icp.yaml @@ -13,4 +13,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/llm_chatbot/frontend/package.json b/motoko/llm_chatbot/frontend/package.json index 8f65ae308c..6fe18a395b 100644 --- a/motoko/llm_chatbot/frontend/package.json +++ b/motoko/llm_chatbot/frontend/package.json @@ -8,14 +8,14 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~6.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1", "react-markdown": "~10.1.0", "remark-gfm": "~4.0.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.4.0", + "@icp-sdk/bindgen": "~0.4.1", "@tailwindcss/typography": "~0.5.20", "@vitejs/plugin-react": "4.3.3", "autoprefixer": "^10.4.20", diff --git a/motoko/llm_chatbot/icp.yaml b/motoko/llm_chatbot/icp.yaml index e3fe8e543b..9919047e00 100644 --- a/motoko/llm_chatbot/icp.yaml +++ b/motoko/llm_chatbot/icp.yaml @@ -11,7 +11,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/low_wasm_memory/icp.yaml b/motoko/low_wasm_memory/icp.yaml index 34d1ae7e65..a408bf0f96 100644 --- a/motoko/low_wasm_memory/icp.yaml +++ b/motoko/low_wasm_memory/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" settings: wasm_memory_limit: 8mib wasm_memory_threshold: 2mib diff --git a/motoko/parallel_calls/icp.yaml b/motoko/parallel_calls/icp.yaml index 13aed299f3..643dd04a6f 100644 --- a/motoko/parallel_calls/icp.yaml +++ b/motoko/parallel_calls/icp.yaml @@ -1,8 +1,8 @@ canisters: - name: caller recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: callee recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/pub-sub/icp.yaml b/motoko/pub-sub/icp.yaml index f109b28d2c..d66db129b7 100644 --- a/motoko/pub-sub/icp.yaml +++ b/motoko/pub-sub/icp.yaml @@ -1,8 +1,8 @@ canisters: - name: publisher recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: subscriber recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/query_stats/icp.yaml b/motoko/query_stats/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/query_stats/icp.yaml +++ b/motoko/query_stats/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/random_maze/frontend/package.json b/motoko/random_maze/frontend/package.json index c98614e9c6..47cd6254aa 100644 --- a/motoko/random_maze/frontend/package.json +++ b/motoko/random_maze/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/motoko/random_maze/icp.yaml b/motoko/random_maze/icp.yaml index 491bcb0316..f4a871c2ed 100644 --- a/motoko/random_maze/icp.yaml +++ b/motoko/random_maze/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/send_http_get/icp.yaml b/motoko/send_http_get/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/send_http_get/icp.yaml +++ b/motoko/send_http_get/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/send_http_post/icp.yaml b/motoko/send_http_post/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/send_http_post/icp.yaml +++ b/motoko/send_http_post/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/superheroes/frontend/package.json b/motoko/superheroes/frontend/package.json index 7bfe8e876e..7100a5e818 100644 --- a/motoko/superheroes/frontend/package.json +++ b/motoko/superheroes/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.2.0", + "@icp-sdk/core": "~6.1.0", "react": "^18.3.1", "react-dom": "^18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@vitejs/plugin-react": "^4.3.4", "vite": "5.4.11" } diff --git a/motoko/superheroes/icp.yaml b/motoko/superheroes/icp.yaml index 491bcb0316..f4a871c2ed 100644 --- a/motoko/superheroes/icp.yaml +++ b/motoko/superheroes/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/threshold-ecdsa/icp.yaml b/motoko/threshold-ecdsa/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/threshold-ecdsa/icp.yaml +++ b/motoko/threshold-ecdsa/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/threshold-schnorr/icp.yaml b/motoko/threshold-schnorr/icp.yaml index fb741fadec..92c2fa343e 100644 --- a/motoko/threshold-schnorr/icp.yaml +++ b/motoko/threshold-schnorr/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" diff --git a/motoko/vetkeys/basic_bls_signing/README.md b/motoko/vetkeys/basic_bls_signing/README.md index c3f1d762f3..e8f8cdadcd 100644 --- a/motoko/vetkeys/basic_bls_signing/README.md +++ b/motoko/vetkeys/basic_bls_signing/README.md @@ -39,6 +39,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/motoko/vetkeys/basic_bls_signing/frontend/package.json b/motoko/vetkeys/basic_bls_signing/frontend/package.json index 0a68d864e4..04a4ff4f0a 100644 --- a/motoko/vetkeys/basic_bls_signing/frontend/package.json +++ b/motoko/vetkeys/basic_bls_signing/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0-beta.0" + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "typescript": "~5.7.2", "vite": "^6.4.1" } diff --git a/motoko/vetkeys/basic_bls_signing/frontend/src/main.ts b/motoko/vetkeys/basic_bls_signing/frontend/src/main.ts index 18c7c4de4d..a2c4a5510e 100644 --- a/motoko/vetkeys/basic_bls_signing/frontend/src/main.ts +++ b/motoko/vetkeys/basic_bls_signing/frontend/src/main.ts @@ -1,6 +1,6 @@ import "./style.css"; import { Principal } from "@icp-sdk/core/principal"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; import { HttpAgent } from "@icp-sdk/core/agent"; import { createActor, type Backend, type Signature } from "./bindings/backend"; import { DerivedPublicKey, verifyBlsSignature } from "@icp-sdk/vetkeys"; @@ -59,15 +59,16 @@ async function initAuth() { const isLocalEnv = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. authClient = new AuthClient({ - identityProvider: isLocalEnv - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocalEnv ? { storage: new LocalStorage(), keyType: "Ed25519" as const } : {}), + identityProvider: { + authorizeUrl: isLocalEnv + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, }); const isAuthenticated = authClient.isAuthenticated(); diff --git a/motoko/vetkeys/basic_bls_signing/icp.yaml b/motoko/vetkeys/basic_bls_signing/icp.yaml index fd456ac78b..11439e3add 100644 --- a/motoko/vetkeys/basic_bls_signing/icp.yaml +++ b/motoko/vetkeys/basic_bls_signing/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" settings: # The vetKD master key this canister derives from, read by the canister via # `Runtime.envVar("VETKD_KEY_NAME")` and captured in stable state at the first diff --git a/motoko/vetkeys/basic_ibe/README.md b/motoko/vetkeys/basic_ibe/README.md index 11377cd68c..9062f04f39 100644 --- a/motoko/vetkeys/basic_ibe/README.md +++ b/motoko/vetkeys/basic_ibe/README.md @@ -40,6 +40,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/motoko/vetkeys/basic_ibe/frontend/package.json b/motoko/vetkeys/basic_ibe/frontend/package.json index 0a68d864e4..04a4ff4f0a 100644 --- a/motoko/vetkeys/basic_ibe/frontend/package.json +++ b/motoko/vetkeys/basic_ibe/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0-beta.0" + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "typescript": "~5.7.2", "vite": "^6.4.1" } diff --git a/motoko/vetkeys/basic_ibe/frontend/src/main.ts b/motoko/vetkeys/basic_ibe/frontend/src/main.ts index 0396ebcb82..d37760c1bd 100644 --- a/motoko/vetkeys/basic_ibe/frontend/src/main.ts +++ b/motoko/vetkeys/basic_ibe/frontend/src/main.ts @@ -10,7 +10,7 @@ import { IbeSeed, } from "@icp-sdk/vetkeys"; import { createActor, type Backend, type Inbox } from "./bindings/backend"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; import { HttpAgent } from "@icp-sdk/core/agent"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; @@ -275,15 +275,16 @@ async function initAuth() { const isLocal = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. authClient = new AuthClient({ - identityProvider: isLocal - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocal ? { storage: new LocalStorage(), keyType: "Ed25519" as const } : {}), + identityProvider: { + authorizeUrl: isLocal + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, }); const isAuthenticated = authClient.isAuthenticated(); diff --git a/motoko/vetkeys/basic_ibe/icp.yaml b/motoko/vetkeys/basic_ibe/icp.yaml index fd456ac78b..11439e3add 100644 --- a/motoko/vetkeys/basic_ibe/icp.yaml +++ b/motoko/vetkeys/basic_ibe/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" settings: # The vetKD master key this canister derives from, read by the canister via # `Runtime.envVar("VETKD_KEY_NAME")` and captured in stable state at the first diff --git a/motoko/vetkeys/basic_vetkd/README.md b/motoko/vetkeys/basic_vetkd/README.md index d22e21c1ea..b0d61f2214 100644 --- a/motoko/vetkeys/basic_vetkd/README.md +++ b/motoko/vetkeys/basic_vetkd/README.md @@ -34,6 +34,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. When done: `icp network stop` ## Updating the Candid interface diff --git a/motoko/vetkeys/basic_vetkd/frontend/package.json b/motoko/vetkeys/basic_vetkd/frontend/package.json index 258c8684c1..8f41708613 100644 --- a/motoko/vetkeys/basic_vetkd/frontend/package.json +++ b/motoko/vetkeys/basic_vetkd/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0-beta.0" + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "vite": "^6.4.1" } } diff --git a/motoko/vetkeys/basic_vetkd/frontend/src/main.js b/motoko/vetkeys/basic_vetkd/frontend/src/main.js index 1de276229b..beeb81f019 100644 --- a/motoko/vetkeys/basic_vetkd/frontend/src/main.js +++ b/motoko/vetkeys/basic_vetkd/frontend/src/main.js @@ -1,7 +1,7 @@ import "./style.css"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import { createActor } from "./bindings/backend"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; import { HttpAgent } from "@icp-sdk/core/agent"; import { Principal } from "@icp-sdk/core/principal"; import { @@ -207,11 +207,16 @@ async function initAuth() { const isLocal = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. authClient = new AuthClient({ - identityProvider: isLocal - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocal ? { storage: new LocalStorage(), keyType: "Ed25519" } : {}), + identityProvider: { + authorizeUrl: isLocal + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, }); if (authClient.isAuthenticated()) { myPrincipal = (await authClient.getIdentity()).getPrincipal(); diff --git a/motoko/vetkeys/basic_vetkd/icp.yaml b/motoko/vetkeys/basic_vetkd/icp.yaml index fd456ac78b..11439e3add 100644 --- a/motoko/vetkeys/basic_vetkd/icp.yaml +++ b/motoko/vetkeys/basic_vetkd/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" settings: # The vetKD master key this canister derives from, read by the canister via # `Runtime.envVar("VETKD_KEY_NAME")` and captured in stable state at the first diff --git a/motoko/vetkeys/encrypted_notes_app_vetkd/README.md b/motoko/vetkeys/encrypted_notes_app_vetkd/README.md index 10f202b9dd..909904f59e 100644 --- a/motoko/vetkeys/encrypted_notes_app_vetkd/README.md +++ b/motoko/vetkeys/encrypted_notes_app_vetkd/README.md @@ -34,6 +34,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/package.json b/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/package.json index a47e8cdc67..beeac766b4 100644 --- a/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/package.json +++ b/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/package.json @@ -10,7 +10,7 @@ "check": "svelte-check --tsconfig ./tsconfig.json" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@sveltejs/vite-plugin-svelte": "^3.0.2", "@tsconfig/svelte": "^5.0.4", "@types/node": "^24.0.10", @@ -24,9 +24,9 @@ "vite": "^5.4.21" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0-beta.0", + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0", "daisyui": "^1.25.4", "idb-keyval": "6.2.1", "isomorphic-dompurify": "^2.25.0", diff --git a/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts b/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts index 88f138897d..4618ed5b2c 100644 --- a/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts +++ b/motoko/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts @@ -1,11 +1,14 @@ import { get, writable } from "svelte/store"; import { type BackendActor, createActor } from "../lib/actor"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import type { Principal } from "@icp-sdk/core/principal"; import { CryptoService } from "../lib/crypto"; import { showError } from "./notifications"; import { push } from "svelte-spa-router"; +const rootKey = safeGetCanisterEnv()?.IC_ROOT_KEY; + export type AuthState = | { state: "initializing-auth" } | { state: "anonymous"; actor: BackendActor; client: AuthClient } @@ -26,17 +29,20 @@ async function initAuth() { const isLocal = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. const client = new AuthClient({ - identityProvider: isLocal - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocal - ? { storage: new LocalStorage(), keyType: "Ed25519" as const } - : {}), + identityProvider: { + authorizeUrl: isLocal + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey }, + }); + // Leave the signed-in views when the session ends, including from another tab. + client.subscribe(() => { + if (!client.isAuthenticated()) void logout(); }); if (client.isAuthenticated()) { authenticate(client); @@ -65,6 +71,8 @@ export async function logout() { const currentAuth = get(auth); if (currentAuth.state === "initialized") { + // Switch first so the session subscription does not sign out twice. + auth.set({ state: "initializing-auth" }); await currentAuth.client.signOut(); const actor = await createActor(); auth.update(() => ({ @@ -77,8 +85,6 @@ export async function logout() { } export async function authenticate(client: AuthClient) { - handleSessionTimeout(); - try { const identity = await client.getIdentity(); const principal = identity.getPrincipal(); @@ -107,26 +113,3 @@ export async function authenticate(client: AuthClient) { })); } } - -function handleSessionTimeout() { - setTimeout(() => { - try { - const delegation = JSON.parse( - window.localStorage.getItem("ic-delegation") ?? "null", - ) as { - delegations: Array<{ delegation: { expiration: string } }>; - } | null; - if (!delegation) return; - - const expirationTimeMs = - Number.parseInt(delegation.delegations[0].delegation.expiration, 16) / - 1000000; - - setTimeout(() => { - logout(); - }, expirationTimeMs - Date.now()); - } catch { - console.error("Could not handle delegation expiry."); - } - }); -} diff --git a/motoko/vetkeys/encrypted_notes_app_vetkd/icp.yaml b/motoko/vetkeys/encrypted_notes_app_vetkd/icp.yaml index fd456ac78b..11439e3add 100644 --- a/motoko/vetkeys/encrypted_notes_app_vetkd/icp.yaml +++ b/motoko/vetkeys/encrypted_notes_app_vetkd/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" settings: # The vetKD master key this canister derives from, read by the canister via # `Runtime.envVar("VETKD_KEY_NAME")` and captured in stable state at the first diff --git a/motoko/vetkeys/password_manager/README.md b/motoko/vetkeys/password_manager/README.md index ee92c2c046..f0209820a0 100644 --- a/motoko/vetkeys/password_manager/README.md +++ b/motoko/vetkeys/password_manager/README.md @@ -36,6 +36,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/motoko/vetkeys/password_manager/frontend/package.json b/motoko/vetkeys/password_manager/frontend/package.json index ba0e1f6b23..46c7e9e9e7 100644 --- a/motoko/vetkeys/password_manager/frontend/package.json +++ b/motoko/vetkeys/password_manager/frontend/package.json @@ -18,9 +18,9 @@ "vite": "^5.4.21" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0-beta.0", + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0", "@popperjs/core": "^2.11.8", "@sveltejs/vite-plugin-svelte": "^3.0.2", "@tailwindcss/postcss": "^4.0.6", diff --git a/motoko/vetkeys/password_manager/frontend/src/store/auth.ts b/motoko/vetkeys/password_manager/frontend/src/store/auth.ts index 54a75e50ae..ebc284a7f0 100644 --- a/motoko/vetkeys/password_manager/frontend/src/store/auth.ts +++ b/motoko/vetkeys/password_manager/frontend/src/store/auth.ts @@ -1,12 +1,14 @@ import "../lib/init.ts"; import { get, writable } from "svelte/store"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; -import { DelegationIdentity } from "@icp-sdk/core/identity"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import type { Principal } from "@icp-sdk/core/principal"; import { replace } from "svelte-spa-router"; import { createEncryptedMaps } from "../lib/encrypted_maps.js"; import { EncryptedMaps } from "@icp-sdk/vetkeys/encrypted_maps"; +const rootKey = safeGetCanisterEnv()?.IC_ROOT_KEY; + export type AuthState = | { state: "initializing-auth"; @@ -34,17 +36,20 @@ async function initAuth() { const isLocalEnv = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. const client = new AuthClient({ - identityProvider: isLocalEnv - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocalEnv - ? { storage: new LocalStorage(), keyType: "Ed25519" as const } - : {}), + identityProvider: { + authorizeUrl: isLocalEnv + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey }, + }); + // Leave the signed-in views when the session ends, including from another tab. + client.subscribe(() => { + if (!client.isAuthenticated()) void logout(); }); if (client.isAuthenticated()) { void authenticate(client); @@ -79,18 +84,17 @@ export async function logout() { const currentAuth = get(auth); if (currentAuth.state === "initialized") { - await currentAuth.client.signOut(); + // Switch first so the session subscription does not sign out twice. auth.update(() => ({ state: "anonymous", client: currentAuth.client, })); + await currentAuth.client.signOut(); void replace("/"); } } export async function authenticate(client: AuthClient) { - void handleSessionTimeout(client); - try { const identity = await client.getIdentity(); const encryptedMaps = await createEncryptedMaps({ identity }); @@ -108,22 +112,3 @@ export async function authenticate(client: AuthClient) { })); } } - -// set a timer when the II session will expire and log the user out -async function handleSessionTimeout(client: AuthClient) { - try { - const identity = await client.getIdentity(); - if (!(identity instanceof DelegationIdentity)) return; - - const chain = identity.getDelegation(); - // expiration is a BigInt of nanoseconds since epoch - const expirationMs = - Number(chain.delegations[0].delegation.expiration) / 1_000_000; - - setTimeout(() => { - void logout(); - }, expirationMs - Date.now()); - } catch { - console.error("Could not handle delegation expiry."); - } -} diff --git a/motoko/vetkeys/password_manager/icp.yaml b/motoko/vetkeys/password_manager/icp.yaml index fd456ac78b..11439e3add 100644 --- a/motoko/vetkeys/password_manager/icp.yaml +++ b/motoko/vetkeys/password_manager/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" settings: # The vetKD master key this canister derives from, read by the canister via # `Runtime.envVar("VETKD_KEY_NAME")` and captured in stable state at the first diff --git a/motoko/vetkeys/password_manager_with_metadata/README.md b/motoko/vetkeys/password_manager_with_metadata/README.md index fe0f4cad91..70f5a3a4b5 100644 --- a/motoko/vetkeys/password_manager_with_metadata/README.md +++ b/motoko/vetkeys/password_manager_with_metadata/README.md @@ -39,6 +39,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/motoko/vetkeys/password_manager_with_metadata/frontend/package.json b/motoko/vetkeys/password_manager_with_metadata/frontend/package.json index adaf711ac4..d1d2d6a3f2 100644 --- a/motoko/vetkeys/password_manager_with_metadata/frontend/package.json +++ b/motoko/vetkeys/password_manager_with_metadata/frontend/package.json @@ -9,7 +9,7 @@ "preview": "vite preview" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@rollup/plugin-typescript": "^12.1.2", "@tailwindcss/postcss": "^4.0.6", "@tailwindcss/vite": "^4.0.0", @@ -21,9 +21,9 @@ "vite": "^5.4.21" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0-beta.0", + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0", "@sveltejs/vite-plugin-svelte": "^3.0.2", "daisyui": "^4.12.23", "svelte": "^4.2.19", diff --git a/motoko/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts b/motoko/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts index 1f54fb574e..f6ab41b664 100644 --- a/motoko/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts +++ b/motoko/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts @@ -1,6 +1,6 @@ import { get, writable } from "svelte/store"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; -import { DelegationIdentity } from "@icp-sdk/core/identity"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import type { Principal } from "@icp-sdk/core/principal"; import { replace } from "svelte-spa-router"; import { @@ -8,6 +8,8 @@ import { createPasswordManager, } from "../lib/password_manager.js"; +const rootKey = safeGetCanisterEnv()?.IC_ROOT_KEY; + export type AuthState = | { state: "initializing-auth"; @@ -35,17 +37,20 @@ async function initAuth() { const isLocalEnv = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. const client = new AuthClient({ - identityProvider: isLocalEnv - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocalEnv - ? { storage: new LocalStorage(), keyType: "Ed25519" as const } - : {}), + identityProvider: { + authorizeUrl: isLocalEnv + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey }, + }); + // Leave the signed-in views when the session ends, including from another tab. + client.subscribe(() => { + if (!client.isAuthenticated()) void logout(); }); if (client.isAuthenticated()) { await authenticate(client); @@ -80,18 +85,17 @@ export async function logout() { const currentAuth = get(auth); if (currentAuth.state === "initialized") { - await currentAuth.client.signOut(); + // Switch first so the session subscription does not sign out twice. auth.update(() => ({ state: "anonymous", client: currentAuth.client, })); + await currentAuth.client.signOut(); await replace("/"); } } export async function authenticate(client: AuthClient) { - void handleSessionTimeout(client); - try { const identity = await client.getIdentity(); const passwordManager = await createPasswordManager({ identity }); @@ -109,22 +113,3 @@ export async function authenticate(client: AuthClient) { })); } } - -// set a timer when the II session will expire and log the user out -async function handleSessionTimeout(client: AuthClient) { - try { - const identity = await client.getIdentity(); - if (!(identity instanceof DelegationIdentity)) return; - - const chain = identity.getDelegation(); - // expiration is a BigInt of nanoseconds since epoch - const expirationMs = - Number(chain.delegations[0].delegation.expiration) / 1_000_000; - - setTimeout(() => { - void logout(); - }, expirationMs - Date.now()); - } catch { - console.error("Could not handle delegation expiry."); - } -} diff --git a/motoko/vetkeys/password_manager_with_metadata/icp.yaml b/motoko/vetkeys/password_manager_with_metadata/icp.yaml index fd456ac78b..11439e3add 100644 --- a/motoko/vetkeys/password_manager_with_metadata/icp.yaml +++ b/motoko/vetkeys/password_manager_with_metadata/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" settings: # The vetKD master key this canister derives from, read by the canister via # `Runtime.envVar("VETKD_KEY_NAME")` and captured in stable state at the first diff --git a/motoko/who_am_i/README.md b/motoko/who_am_i/README.md index f036142bf6..570db6d718 100644 --- a/motoko/who_am_i/README.md +++ b/motoko/who_am_i/README.md @@ -33,6 +33,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: ```bash diff --git a/motoko/who_am_i/icp.yaml b/motoko/who_am_i/icp.yaml index 0987be668c..2302e4c7c0 100644 --- a/motoko/who_am_i/icp.yaml +++ b/motoko/who_am_i/icp.yaml @@ -6,7 +6,7 @@ networks: canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: frontend recipe: diff --git a/motoko/who_am_i/src/frontend/package.json b/motoko/who_am_i/src/frontend/package.json index 412b87e6d0..d4df8d9d58 100644 --- a/motoko/who_am_i/src/frontend/package.json +++ b/motoko/who_am_i/src/frontend/package.json @@ -8,13 +8,13 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "~5.0.0", - "@icp-sdk/core": "~5.2.0", + "@icp-sdk/auth": "~10.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.3.0", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/motoko/who_am_i/src/frontend/src/App.jsx b/motoko/who_am_i/src/frontend/src/App.jsx index 08af5ce2e0..7564430b8b 100644 --- a/motoko/who_am_i/src/frontend/src/App.jsx +++ b/motoko/who_am_i/src/frontend/src/App.jsx @@ -1,61 +1,35 @@ import React, { useState, useEffect } from 'react'; -import { AuthClient } from '@icp-sdk/auth/client'; -import { createBackendActor, identityProviderUrl } from './actor'; +import { authClient, createBackendActor } from './actor'; // Reusable button component const Button = ({ onClick, children }) => ; const App = () => { - const [state, setState] = useState({ - actor: undefined, - authClient: undefined, - isAuthenticated: false, - principal: 'Click "Whoami" to see your principal ID' - }); + const [isAuthenticated, setIsAuthenticated] = useState(authClient.isAuthenticated()); + const [principal, setPrincipal] = useState('Click "Whoami" to see your principal ID'); - // Initialize auth client - useEffect(() => { - updateActor(); - }, []); - - const updateActor = async () => { - const authClient = await AuthClient.create(); - const identity = authClient.getIdentity(); - const actor = createBackendActor(identity); - const isAuthenticated = await authClient.isAuthenticated(); - - setState((prev) => ({ - ...prev, - actor, - authClient, - isAuthenticated - })); - }; + // Track the sign-in status, including changes made in another tab. + useEffect(() => authClient.subscribe(() => setIsAuthenticated(authClient.isAuthenticated())), []); const login = async () => { - await state.authClient.login({ - identityProvider: identityProviderUrl, - onSuccess: updateActor - }); + try { + await authClient.signIn(); + } catch (error) { + console.error('Sign-in failed:', error); + } }; const logout = async () => { - await state.authClient.logout(); - updateActor(); + await authClient.signOut(); }; const whoami = async () => { - setState((prev) => ({ - ...prev, - principal: 'Loading...' - })); + setPrincipal('Loading...'); - const result = await state.actor.whoami(); - const principal = result.toString(); - setState((prev) => ({ - ...prev, - principal - })); + // Read the identity at call time: it is installed only once signIn() completes. + const identity = authClient.isAuthenticated() ? await authClient.getIdentity() : undefined; + const result = await createBackendActor(identity).whoami(); + setPrincipal(result.toString()); }; return ( @@ -82,7 +56,7 @@ const App = () => { - {!state.isAuthenticated ? ( + {!isAuthenticated ? ( ) : ( @@ -90,10 +64,10 @@ const App = () => { - {state.principal && ( + {principal && (

Your principal ID is:

-

{state.principal}

+

{principal}

)} diff --git a/motoko/who_am_i/src/frontend/src/actor.js b/motoko/who_am_i/src/frontend/src/actor.js index e3a4d83306..6994e2f861 100644 --- a/motoko/who_am_i/src/frontend/src/actor.js +++ b/motoko/who_am_i/src/frontend/src/actor.js @@ -1,3 +1,4 @@ +import { AuthClient } from "@icp-sdk/auth/client"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import { createActor } from "./bindings/backend"; @@ -16,19 +17,26 @@ const agentOptions = { rootKey: canisterEnv?.IC_ROOT_KEY, }; -// Resolve Internet Identity provider URL. -// II is always deployed on the local network (not the dev server). +// Internet Identity is deployed on the local network (`ii: true` in icp.yaml). // REPLICA_PORT is injected by vite.config.js during `vite dev` since // window.location.port would be the dev server port, not the network port. const isLocal = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.endsWith(".localhost"); -const II_CANISTER_ID = "uqzsh-gqaaa-aaaaq-qaada-cai"; const networkPort = process.env.REPLICA_PORT || window.location.port; -export const identityProviderUrl = isLocal - ? `http://${II_CANISTER_ID}.localhost:${networkPort}` - : "https://id.ai"; + +// The client mints its delegations by calling the II canister, so its agent +// needs the network's root key to verify the responses. +export const authClient = new AuthClient({ + identityProvider: { + authorizeUrl: isLocal + ? `http://id.ai.localhost:${networkPort}/authorize` + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, +}); export function createBackendActor(identity) { return createActor(canisterId, { diff --git a/native-apps/unity_ii_deeplink/icp.yaml b/native-apps/unity_ii_deeplink/icp.yaml index 8bde9771e0..9db1c99830 100644 --- a/native-apps/unity_ii_deeplink/icp.yaml +++ b/native-apps/unity_ii_deeplink/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v5.0.0" + type: "@dfinity/motoko@v5.1.0" - name: ii-bridge recipe: diff --git a/rust/backend_only/icp.yaml b/rust/backend_only/icp.yaml index ff944789f1..bbb0414d98 100644 --- a/rust/backend_only/icp.yaml +++ b/rust/backend_only/icp.yaml @@ -1,6 +1,6 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.2.0" + type: "@dfinity/rust@v3.4.0" configuration: package: backend diff --git a/rust/basic_bitcoin/icp.yaml b/rust/basic_bitcoin/icp.yaml index 341ab9a7bb..a0e693cf27 100644 --- a/rust/basic_bitcoin/icp.yaml +++ b/rust/basic_bitcoin/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" networks: - name: local diff --git a/rust/basic_ethereum/icp.yaml b/rust/basic_ethereum/icp.yaml index 231dbd70f0..c52b4366e6 100644 --- a/rust/basic_ethereum/icp.yaml +++ b/rust/basic_ethereum/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" # evm_rpc is only deployed locally. On ICP mainnet the shared EVM RPC canister # (7hfb6-caaaa-aaaar-qadga-cai) is used instead — the ic environment below diff --git a/rust/candid_type_generation/icp.yaml b/rust/candid_type_generation/icp.yaml index 82630e5291..9aff98f236 100644 --- a/rust/candid_type_generation/icp.yaml +++ b/rust/candid_type_generation/icp.yaml @@ -6,6 +6,6 @@ networks: canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: package: backend diff --git a/rust/canister-info/icp.yaml b/rust/canister-info/icp.yaml index 26c5572db1..d1418f33e7 100644 --- a/rust/canister-info/icp.yaml +++ b/rust/canister-info/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" # test is a pre-built canister that provides a subject for the backend's # canister_info queries in test.sh. It is deployed locally only (see the diff --git a/rust/canister-snapshot-download/icp.yaml b/rust/canister-snapshot-download/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/canister-snapshot-download/icp.yaml +++ b/rust/canister-snapshot-download/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/canister-snapshots/icp.yaml b/rust/canister-snapshots/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/canister-snapshots/icp.yaml +++ b/rust/canister-snapshots/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/canister_logs/icp.yaml b/rust/canister_logs/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/canister_logs/icp.yaml +++ b/rust/canister_logs/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/daily_planner/frontend/package.json b/rust/daily_planner/frontend/package.json index 859836e9b9..47cd6254aa 100644 --- a/rust/daily_planner/frontend/package.json +++ b/rust/daily_planner/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.2.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/rust/daily_planner/icp.yaml b/rust/daily_planner/icp.yaml index a1060e6e60..d5697599e0 100644 --- a/rust/daily_planner/icp.yaml +++ b/rust/daily_planner/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did diff --git a/rust/evm_block_explorer/frontend/package.json b/rust/evm_block_explorer/frontend/package.json index 409c199831..61c36672ee 100644 --- a/rust/evm_block_explorer/frontend/package.json +++ b/rust/evm_block_explorer/frontend/package.json @@ -8,13 +8,13 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1", "react-json-view-lite": "2.3.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/rust/evm_block_explorer/icp.yaml b/rust/evm_block_explorer/icp.yaml index 92f34d364a..3c009edf01 100644 --- a/rust/evm_block_explorer/icp.yaml +++ b/rust/evm_block_explorer/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did diff --git a/rust/exchange-rates/icp.yaml b/rust/exchange-rates/icp.yaml index 384b7a1ae6..ed36905fd9 100644 --- a/rust/exchange-rates/icp.yaml +++ b/rust/exchange-rates/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" # xrc_mock is only deployed locally. On IC mainnet the production XRC canister # (uf6dk-hyaaa-aaaaq-qaaaq-cai) is used instead — the ic environment below diff --git a/rust/face-recognition/frontend/package.json b/rust/face-recognition/frontend/package.json index 87cf2ed1a3..1f9ebb977c 100644 --- a/rust/face-recognition/frontend/package.json +++ b/rust/face-recognition/frontend/package.json @@ -8,10 +8,10 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.4.0" + "@icp-sdk/core": "~6.1.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.4.0", + "@icp-sdk/bindgen": "~0.4.1", "vite": "8.1.3" } } diff --git a/rust/flying_ninja/frontend/package.json b/rust/flying_ninja/frontend/package.json index c98614e9c6..47cd6254aa 100644 --- a/rust/flying_ninja/frontend/package.json +++ b/rust/flying_ninja/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/rust/flying_ninja/icp.yaml b/rust/flying_ninja/icp.yaml index 280711f4e0..77d63332dc 100644 --- a/rust/flying_ninja/icp.yaml +++ b/rust/flying_ninja/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.2.0" + type: "@dfinity/rust@v3.4.0" configuration: package: backend candid: backend/backend.did diff --git a/rust/guards/icp.yaml b/rust/guards/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/guards/icp.yaml +++ b/rust/guards/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/hello_world/frontend/package.json b/rust/hello_world/frontend/package.json index d0cc35cdb0..c5f9d65ed9 100644 --- a/rust/hello_world/frontend/package.json +++ b/rust/hello_world/frontend/package.json @@ -8,10 +8,10 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.0.0" + "@icp-sdk/core": "~6.1.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "vite": "5.4.11" } } diff --git a/rust/hello_world/icp.yaml b/rust/hello_world/icp.yaml index 280711f4e0..77d63332dc 100644 --- a/rust/hello_world/icp.yaml +++ b/rust/hello_world/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.2.0" + type: "@dfinity/rust@v3.4.0" configuration: package: backend candid: backend/backend.did diff --git a/rust/icp_transfer/icp.yaml b/rust/icp_transfer/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/icp_transfer/icp.yaml +++ b/rust/icp_transfer/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/image-classification/frontend/package.json b/rust/image-classification/frontend/package.json index 87cf2ed1a3..1f9ebb977c 100644 --- a/rust/image-classification/frontend/package.json +++ b/rust/image-classification/frontend/package.json @@ -8,10 +8,10 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.4.0" + "@icp-sdk/core": "~6.1.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.4.0", + "@icp-sdk/bindgen": "~0.4.1", "vite": "8.1.3" } } diff --git a/rust/inter-canister-calls/icp.yaml b/rust/inter-canister-calls/icp.yaml index e6618c250c..d99713f758 100644 --- a/rust/inter-canister-calls/icp.yaml +++ b/rust/inter-canister-calls/icp.yaml @@ -1,8 +1,8 @@ canisters: - name: counter recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" - name: caller recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/llm_chatbot/frontend/package.json b/rust/llm_chatbot/frontend/package.json index 8f65ae308c..6fe18a395b 100644 --- a/rust/llm_chatbot/frontend/package.json +++ b/rust/llm_chatbot/frontend/package.json @@ -8,14 +8,14 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~6.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1", "react-markdown": "~10.1.0", "remark-gfm": "~4.0.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.4.0", + "@icp-sdk/bindgen": "~0.4.1", "@tailwindcss/typography": "~0.5.20", "@vitejs/plugin-react": "4.3.3", "autoprefixer": "^10.4.20", diff --git a/rust/llm_chatbot/icp.yaml b/rust/llm_chatbot/icp.yaml index 9c8c7ebb17..1b4209b6b6 100644 --- a/rust/llm_chatbot/icp.yaml +++ b/rust/llm_chatbot/icp.yaml @@ -11,7 +11,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did diff --git a/rust/low_wasm_memory/icp.yaml b/rust/low_wasm_memory/icp.yaml index 81e9cfba3e..4ec6124eae 100644 --- a/rust/low_wasm_memory/icp.yaml +++ b/rust/low_wasm_memory/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" settings: wasm_memory_limit: 8mib wasm_memory_threshold: 2mib diff --git a/rust/parallel_calls/icp.yaml b/rust/parallel_calls/icp.yaml index 9142a8a485..59b6a44d35 100644 --- a/rust/parallel_calls/icp.yaml +++ b/rust/parallel_calls/icp.yaml @@ -1,8 +1,8 @@ canisters: - name: caller recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" - name: callee recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/performance_counters/icp.yaml b/rust/performance_counters/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/performance_counters/icp.yaml +++ b/rust/performance_counters/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/periodic_tasks/icp.yaml b/rust/periodic_tasks/icp.yaml index 4bc0e973fd..988c6b824f 100644 --- a/rust/periodic_tasks/icp.yaml +++ b/rust/periodic_tasks/icp.yaml @@ -1,10 +1,10 @@ canisters: - name: timer recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" init_args: "(10 : nat64)" - name: heartbeat recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" init_args: "(10 : nat64)" diff --git a/rust/photo_gallery/frontend/package.json b/rust/photo_gallery/frontend/package.json index ab8e5906b8..6836256a22 100644 --- a/rust/photo_gallery/frontend/package.json +++ b/rust/photo_gallery/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.2.0", + "@icp-sdk/core": "~6.1.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "@vitejs/plugin-react": "^4.0.1", diff --git a/rust/photo_gallery/icp.yaml b/rust/photo_gallery/icp.yaml index a1060e6e60..d5697599e0 100644 --- a/rust/photo_gallery/icp.yaml +++ b/rust/photo_gallery/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did diff --git a/rust/qrcode/frontend/package.json b/rust/qrcode/frontend/package.json index 38b23697d7..c5f9d65ed9 100644 --- a/rust/qrcode/frontend/package.json +++ b/rust/qrcode/frontend/package.json @@ -8,10 +8,10 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/core": "~5.2.0" + "@icp-sdk/core": "~6.1.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.3.0", + "@icp-sdk/bindgen": "~0.4.1", "vite": "5.4.11" } } diff --git a/rust/qrcode/icp.yaml b/rust/qrcode/icp.yaml index 30fdb4a827..cd46f8ef08 100644 --- a/rust/qrcode/icp.yaml +++ b/rust/qrcode/icp.yaml @@ -5,7 +5,7 @@ networks: canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did diff --git a/rust/query_stats/icp.yaml b/rust/query_stats/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/query_stats/icp.yaml +++ b/rust/query_stats/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/receiving-icp/icp.yaml b/rust/receiving-icp/icp.yaml index 6dbef3e7f6..e13a36b514 100644 --- a/rust/receiving-icp/icp.yaml +++ b/rust/receiving-icp/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" # ICP_LEDGER_CANISTER_ID is injected at deploy time and read at runtime via # ic_cdk::api::env_var_value("ICP_LEDGER_CANISTER_ID"). diff --git a/rust/send_http_flexible/icp.yaml b/rust/send_http_flexible/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/send_http_flexible/icp.yaml +++ b/rust/send_http_flexible/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/send_http_get/icp.yaml b/rust/send_http_get/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/send_http_get/icp.yaml +++ b/rust/send_http_get/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/send_http_post/icp.yaml b/rust/send_http_post/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/send_http_post/icp.yaml +++ b/rust/send_http_post/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/simd/icp.yaml b/rust/simd/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/simd/icp.yaml +++ b/rust/simd/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/threshold-ecdsa/icp.yaml b/rust/threshold-ecdsa/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/threshold-ecdsa/icp.yaml +++ b/rust/threshold-ecdsa/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/threshold-schnorr/icp.yaml b/rust/threshold-schnorr/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/threshold-schnorr/icp.yaml +++ b/rust/threshold-schnorr/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/unit_testable_rust_canister/icp.yaml b/rust/unit_testable_rust_canister/icp.yaml index b7c87727a0..293fd42b10 100644 --- a/rust/unit_testable_rust_canister/icp.yaml +++ b/rust/unit_testable_rust_canister/icp.yaml @@ -1,4 +1,4 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" diff --git a/rust/vetkeys/basic_bls_signing/README.md b/rust/vetkeys/basic_bls_signing/README.md index d92bfc5939..2a52a5c576 100644 --- a/rust/vetkeys/basic_bls_signing/README.md +++ b/rust/vetkeys/basic_bls_signing/README.md @@ -37,6 +37,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/rust/vetkeys/basic_bls_signing/frontend/package.json b/rust/vetkeys/basic_bls_signing/frontend/package.json index 16390882d0..04a4ff4f0a 100644 --- a/rust/vetkeys/basic_bls_signing/frontend/package.json +++ b/rust/vetkeys/basic_bls_signing/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0" + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "typescript": "~5.7.2", "vite": "^6.4.1" } diff --git a/rust/vetkeys/basic_bls_signing/frontend/src/main.ts b/rust/vetkeys/basic_bls_signing/frontend/src/main.ts index fea6e11069..0e4e834f9b 100644 --- a/rust/vetkeys/basic_bls_signing/frontend/src/main.ts +++ b/rust/vetkeys/basic_bls_signing/frontend/src/main.ts @@ -1,6 +1,6 @@ import "./style.css"; import { Principal } from "@icp-sdk/core/principal"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; import { HttpAgent } from "@icp-sdk/core/agent"; import { createActor, type Backend, type Signature } from "./bindings/backend"; import { DerivedPublicKey, verifyBlsSignature } from "@icp-sdk/vetkeys"; @@ -59,15 +59,16 @@ async function initAuth() { const isLocalEnv = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. authClient = new AuthClient({ - identityProvider: isLocalEnv - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocalEnv ? { storage: new LocalStorage(), keyType: "Ed25519" as const } : {}), + identityProvider: { + authorizeUrl: isLocalEnv + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, }); const isAuthenticated = authClient.isAuthenticated(); diff --git a/rust/vetkeys/basic_bls_signing/icp.yaml b/rust/vetkeys/basic_bls_signing/icp.yaml index e5fb6a9169..f529bf0ad3 100644 --- a/rust/vetkeys/basic_bls_signing/icp.yaml +++ b/rust/vetkeys/basic_bls_signing/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did init_args: diff --git a/rust/vetkeys/basic_ibe/README.md b/rust/vetkeys/basic_ibe/README.md index bd0720fa99..3a85da0fe3 100644 --- a/rust/vetkeys/basic_ibe/README.md +++ b/rust/vetkeys/basic_ibe/README.md @@ -38,6 +38,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/rust/vetkeys/basic_ibe/frontend/package.json b/rust/vetkeys/basic_ibe/frontend/package.json index 16390882d0..04a4ff4f0a 100644 --- a/rust/vetkeys/basic_ibe/frontend/package.json +++ b/rust/vetkeys/basic_ibe/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0" + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "typescript": "~5.7.2", "vite": "^6.4.1" } diff --git a/rust/vetkeys/basic_ibe/frontend/src/main.ts b/rust/vetkeys/basic_ibe/frontend/src/main.ts index f9c3231898..84b586974d 100644 --- a/rust/vetkeys/basic_ibe/frontend/src/main.ts +++ b/rust/vetkeys/basic_ibe/frontend/src/main.ts @@ -10,7 +10,7 @@ import { IbeSeed, } from "@icp-sdk/vetkeys"; import { createActor, type Backend, type Inbox } from "./bindings/backend"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; import { HttpAgent } from "@icp-sdk/core/agent"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; @@ -275,15 +275,16 @@ async function initAuth() { const isLocal = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. authClient = new AuthClient({ - identityProvider: isLocal - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocal ? { storage: new LocalStorage(), keyType: "Ed25519" as const } : {}), + identityProvider: { + authorizeUrl: isLocal + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, }); const isAuthenticated = authClient.isAuthenticated(); diff --git a/rust/vetkeys/basic_ibe/icp.yaml b/rust/vetkeys/basic_ibe/icp.yaml index e5fb6a9169..f529bf0ad3 100644 --- a/rust/vetkeys/basic_ibe/icp.yaml +++ b/rust/vetkeys/basic_ibe/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did init_args: diff --git a/rust/vetkeys/basic_timelock_ibe/README.md b/rust/vetkeys/basic_timelock_ibe/README.md index 69142eb31c..5cf10ae61b 100644 --- a/rust/vetkeys/basic_timelock_ibe/README.md +++ b/rust/vetkeys/basic_timelock_ibe/README.md @@ -57,6 +57,8 @@ basic_timelock_ibe/ icp network start -d && icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + To run the frontend in development mode with hot reloading (after running `icp deploy`): ```bash cd frontend diff --git a/rust/vetkeys/basic_timelock_ibe/frontend/package.json b/rust/vetkeys/basic_timelock_ibe/frontend/package.json index 592ff0d587..b897e8042b 100644 --- a/rust/vetkeys/basic_timelock_ibe/frontend/package.json +++ b/rust/vetkeys/basic_timelock_ibe/frontend/package.json @@ -24,8 +24,8 @@ "vite": "^6.4.1" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0" + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0" } } diff --git a/rust/vetkeys/basic_timelock_ibe/frontend/src/main.ts b/rust/vetkeys/basic_timelock_ibe/frontend/src/main.ts index f04f8d6361..71d23845bf 100644 --- a/rust/vetkeys/basic_timelock_ibe/frontend/src/main.ts +++ b/rust/vetkeys/basic_timelock_ibe/frontend/src/main.ts @@ -7,7 +7,7 @@ import { IbeIdentity, IbeSeed, } from "@icp-sdk/vetkeys"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import { HttpAgent } from "@icp-sdk/core/agent"; @@ -64,13 +64,16 @@ export function logout() { async function initAuth() { const isLocalEnv = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. authClient = new AuthClient({ - identityProvider: isLocalEnv ? "http://id.ai.localhost:8000/authorize" : "https://id.ai/authorize", - ...(isLocalEnv ? { storage: new LocalStorage(), keyType: "Ed25519" as const } : {}), + identityProvider: { + authorizeUrl: isLocalEnv + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, }); const isAuthenticated = authClient.isAuthenticated(); diff --git a/rust/vetkeys/basic_timelock_ibe/icp.yaml b/rust/vetkeys/basic_timelock_ibe/icp.yaml index 289a706cc0..c39650f034 100644 --- a/rust/vetkeys/basic_timelock_ibe/icp.yaml +++ b/rust/vetkeys/basic_timelock_ibe/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: basic_timelock_ibe recipe: - type: "@dfinity/rust@v3.2.0" + type: "@dfinity/rust@v3.4.0" configuration: package: ic-vetkd-example-basic-timelock-ibe-backend candid: backend/backend.did diff --git a/rust/vetkeys/basic_vetkd/README.md b/rust/vetkeys/basic_vetkd/README.md index 3e6bc707bf..690184bed7 100644 --- a/rust/vetkeys/basic_vetkd/README.md +++ b/rust/vetkeys/basic_vetkd/README.md @@ -27,6 +27,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. When done: `icp network stop` ## Updating the Candid interface diff --git a/rust/vetkeys/basic_vetkd/frontend/package.json b/rust/vetkeys/basic_vetkd/frontend/package.json index 7936b17ac1..8f41708613 100644 --- a/rust/vetkeys/basic_vetkd/frontend/package.json +++ b/rust/vetkeys/basic_vetkd/frontend/package.json @@ -8,12 +8,12 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0" + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "vite": "^6.4.1" } } diff --git a/rust/vetkeys/basic_vetkd/frontend/src/main.js b/rust/vetkeys/basic_vetkd/frontend/src/main.js index 1de276229b..beeb81f019 100644 --- a/rust/vetkeys/basic_vetkd/frontend/src/main.js +++ b/rust/vetkeys/basic_vetkd/frontend/src/main.js @@ -1,7 +1,7 @@ import "./style.css"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import { createActor } from "./bindings/backend"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; import { HttpAgent } from "@icp-sdk/core/agent"; import { Principal } from "@icp-sdk/core/principal"; import { @@ -207,11 +207,16 @@ async function initAuth() { const isLocal = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. authClient = new AuthClient({ - identityProvider: isLocal - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocal ? { storage: new LocalStorage(), keyType: "Ed25519" } : {}), + identityProvider: { + authorizeUrl: isLocal + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, }); if (authClient.isAuthenticated()) { myPrincipal = (await authClient.getIdentity()).getPrincipal(); diff --git a/rust/vetkeys/basic_vetkd/icp.yaml b/rust/vetkeys/basic_vetkd/icp.yaml index c9bf6568f1..df00256695 100644 --- a/rust/vetkeys/basic_vetkd/icp.yaml +++ b/rust/vetkeys/basic_vetkd/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.2.0" + type: "@dfinity/rust@v3.4.0" configuration: package: backend candid: backend/backend.did diff --git a/rust/vetkeys/encrypted_notes_app_vetkd/README.md b/rust/vetkeys/encrypted_notes_app_vetkd/README.md index 7dca1834ba..8f951ab611 100644 --- a/rust/vetkeys/encrypted_notes_app_vetkd/README.md +++ b/rust/vetkeys/encrypted_notes_app_vetkd/README.md @@ -28,6 +28,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/rust/vetkeys/encrypted_notes_app_vetkd/frontend/package.json b/rust/vetkeys/encrypted_notes_app_vetkd/frontend/package.json index eced20f0c7..beeac766b4 100644 --- a/rust/vetkeys/encrypted_notes_app_vetkd/frontend/package.json +++ b/rust/vetkeys/encrypted_notes_app_vetkd/frontend/package.json @@ -10,7 +10,7 @@ "check": "svelte-check --tsconfig ./tsconfig.json" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@sveltejs/vite-plugin-svelte": "^3.0.2", "@tsconfig/svelte": "^5.0.4", "@types/node": "^24.0.10", @@ -24,9 +24,9 @@ "vite": "^5.4.21" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0", + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0", "daisyui": "^1.25.4", "idb-keyval": "6.2.1", "isomorphic-dompurify": "^2.25.0", diff --git a/rust/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts b/rust/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts index 88f138897d..4618ed5b2c 100644 --- a/rust/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts +++ b/rust/vetkeys/encrypted_notes_app_vetkd/frontend/src/store/auth.ts @@ -1,11 +1,14 @@ import { get, writable } from "svelte/store"; import { type BackendActor, createActor } from "../lib/actor"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import type { Principal } from "@icp-sdk/core/principal"; import { CryptoService } from "../lib/crypto"; import { showError } from "./notifications"; import { push } from "svelte-spa-router"; +const rootKey = safeGetCanisterEnv()?.IC_ROOT_KEY; + export type AuthState = | { state: "initializing-auth" } | { state: "anonymous"; actor: BackendActor; client: AuthClient } @@ -26,17 +29,20 @@ async function initAuth() { const isLocal = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. const client = new AuthClient({ - identityProvider: isLocal - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocal - ? { storage: new LocalStorage(), keyType: "Ed25519" as const } - : {}), + identityProvider: { + authorizeUrl: isLocal + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey }, + }); + // Leave the signed-in views when the session ends, including from another tab. + client.subscribe(() => { + if (!client.isAuthenticated()) void logout(); }); if (client.isAuthenticated()) { authenticate(client); @@ -65,6 +71,8 @@ export async function logout() { const currentAuth = get(auth); if (currentAuth.state === "initialized") { + // Switch first so the session subscription does not sign out twice. + auth.set({ state: "initializing-auth" }); await currentAuth.client.signOut(); const actor = await createActor(); auth.update(() => ({ @@ -77,8 +85,6 @@ export async function logout() { } export async function authenticate(client: AuthClient) { - handleSessionTimeout(); - try { const identity = await client.getIdentity(); const principal = identity.getPrincipal(); @@ -107,26 +113,3 @@ export async function authenticate(client: AuthClient) { })); } } - -function handleSessionTimeout() { - setTimeout(() => { - try { - const delegation = JSON.parse( - window.localStorage.getItem("ic-delegation") ?? "null", - ) as { - delegations: Array<{ delegation: { expiration: string } }>; - } | null; - if (!delegation) return; - - const expirationTimeMs = - Number.parseInt(delegation.delegations[0].delegation.expiration, 16) / - 1000000; - - setTimeout(() => { - logout(); - }, expirationTimeMs - Date.now()); - } catch { - console.error("Could not handle delegation expiry."); - } - }); -} diff --git a/rust/vetkeys/encrypted_notes_app_vetkd/icp.yaml b/rust/vetkeys/encrypted_notes_app_vetkd/icp.yaml index e5fb6a9169..f529bf0ad3 100644 --- a/rust/vetkeys/encrypted_notes_app_vetkd/icp.yaml +++ b/rust/vetkeys/encrypted_notes_app_vetkd/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did init_args: diff --git a/rust/vetkeys/password_manager/README.md b/rust/vetkeys/password_manager/README.md index 70bdc7e92d..0b460a61db 100644 --- a/rust/vetkeys/password_manager/README.md +++ b/rust/vetkeys/password_manager/README.md @@ -34,6 +34,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/rust/vetkeys/password_manager/frontend/package.json b/rust/vetkeys/password_manager/frontend/package.json index 3d671be29a..46c7e9e9e7 100644 --- a/rust/vetkeys/password_manager/frontend/package.json +++ b/rust/vetkeys/password_manager/frontend/package.json @@ -18,9 +18,9 @@ "vite": "^5.4.21" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0", + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0", "@popperjs/core": "^2.11.8", "@sveltejs/vite-plugin-svelte": "^3.0.2", "@tailwindcss/postcss": "^4.0.6", diff --git a/rust/vetkeys/password_manager/frontend/src/store/auth.ts b/rust/vetkeys/password_manager/frontend/src/store/auth.ts index 9634492e55..cdd53b818b 100644 --- a/rust/vetkeys/password_manager/frontend/src/store/auth.ts +++ b/rust/vetkeys/password_manager/frontend/src/store/auth.ts @@ -1,12 +1,14 @@ import "../lib/init.ts"; import { get, writable } from "svelte/store"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; -import { DelegationIdentity } from "@icp-sdk/core/identity"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import type { Principal } from "@icp-sdk/core/principal"; import { replace } from "svelte-spa-router"; import { createEncryptedMaps } from "../lib/encrypted_maps.js"; import { EncryptedMaps } from "@icp-sdk/vetkeys/encrypted_maps"; +const rootKey = safeGetCanisterEnv()?.IC_ROOT_KEY; + export type AuthState = | { state: "initializing-auth"; @@ -34,17 +36,20 @@ async function initAuth() { const isLocalEnv = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. const client = new AuthClient({ - identityProvider: isLocalEnv - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocalEnv - ? { storage: new LocalStorage(), keyType: "Ed25519" as const } - : {}), + identityProvider: { + authorizeUrl: isLocalEnv + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey }, + }); + // Leave the signed-in views when the session ends, including from another tab. + client.subscribe(() => { + if (!client.isAuthenticated()) void logout(); }); if (client.isAuthenticated()) { void authenticate(client); @@ -79,6 +84,11 @@ export async function logout() { const currentAuth = get(auth); if (currentAuth.state === "initialized") { + // Switch first so the session subscription does not sign out twice. + auth.update(() => ({ + state: "anonymous", + client: currentAuth.client, + })); // Best-effort: drop cached derived key material so a persisted // (IndexedDB) handle can no longer be used to decrypt after logout. This // must not block sign-out if IndexedDB is unavailable (private mode, @@ -89,17 +99,11 @@ export async function logout() { console.error("Failed to clear derived-key cache on logout:", e); } await currentAuth.client.signOut(); - auth.update(() => ({ - state: "anonymous", - client: currentAuth.client, - })); void replace("/"); } } export async function authenticate(client: AuthClient) { - void handleSessionTimeout(client); - try { const identity = await client.getIdentity(); const encryptedMaps = await createEncryptedMaps(identity); @@ -117,22 +121,3 @@ export async function authenticate(client: AuthClient) { })); } } - -// set a timer when the II session will expire and log the user out -async function handleSessionTimeout(client: AuthClient) { - try { - const identity = await client.getIdentity(); - if (!(identity instanceof DelegationIdentity)) return; - - const chain = identity.getDelegation(); - // expiration is a BigInt of nanoseconds since epoch - const expirationMs = - Number(chain.delegations[0].delegation.expiration) / 1_000_000; - - setTimeout(() => { - void logout(); - }, expirationMs - Date.now()); - } catch { - console.error("Could not handle delegation expiry."); - } -} diff --git a/rust/vetkeys/password_manager/icp.yaml b/rust/vetkeys/password_manager/icp.yaml index e5fb6a9169..f529bf0ad3 100644 --- a/rust/vetkeys/password_manager/icp.yaml +++ b/rust/vetkeys/password_manager/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did init_args: diff --git a/rust/vetkeys/password_manager_with_metadata/README.md b/rust/vetkeys/password_manager_with_metadata/README.md index 8693b606c0..541b864da4 100644 --- a/rust/vetkeys/password_manager_with_metadata/README.md +++ b/rust/vetkeys/password_manager_with_metadata/README.md @@ -37,6 +37,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + Open the frontend URL printed by `icp deploy`. To run the frontend in development mode with hot reloading (after `icp deploy`): diff --git a/rust/vetkeys/password_manager_with_metadata/frontend/package.json b/rust/vetkeys/password_manager_with_metadata/frontend/package.json index d0944300aa..d1d2d6a3f2 100644 --- a/rust/vetkeys/password_manager_with_metadata/frontend/package.json +++ b/rust/vetkeys/password_manager_with_metadata/frontend/package.json @@ -9,7 +9,7 @@ "preview": "vite preview" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.2.2", + "@icp-sdk/bindgen": "~0.4.1", "@rollup/plugin-typescript": "^12.1.2", "@tailwindcss/postcss": "^4.0.6", "@tailwindcss/vite": "^4.0.0", @@ -21,9 +21,9 @@ "vite": "^5.4.21" }, "dependencies": { - "@icp-sdk/auth": "^7.1.0", - "@icp-sdk/core": "^5.4.0", - "@icp-sdk/vetkeys": "^0.5.0", + "@icp-sdk/auth": "^10.0.0", + "@icp-sdk/core": "^6.1.0", + "@icp-sdk/vetkeys": "^0.7.0", "@sveltejs/vite-plugin-svelte": "^3.0.2", "daisyui": "^4.12.23", "svelte": "^4.2.19", diff --git a/rust/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts b/rust/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts index 8beea52a6f..01b4a9d1a1 100644 --- a/rust/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts +++ b/rust/vetkeys/password_manager_with_metadata/frontend/src/store/auth.ts @@ -1,6 +1,6 @@ import { get, writable } from "svelte/store"; -import { AuthClient, LocalStorage } from "@icp-sdk/auth/client"; -import { DelegationIdentity } from "@icp-sdk/core/identity"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import type { Principal } from "@icp-sdk/core/principal"; import { replace } from "svelte-spa-router"; import { @@ -8,6 +8,8 @@ import { createPasswordManager, } from "../lib/password_manager.js"; +const rootKey = safeGetCanisterEnv()?.IC_ROOT_KEY; + export type AuthState = | { state: "initializing-auth"; @@ -35,17 +37,20 @@ async function initAuth() { const isLocalEnv = window.location.hostname === "localhost" || window.location.hostname.endsWith(".localhost"); - // Workaround for https://github.com/dfinity/icp-js-auth/issues/120 - // IdbStorage has a race condition on localhost dev servers. LocalStorage - // avoids IDB on local but uses plain string storage (less secure), so - // production deployments keep the default secure IdbStorage + ECDSA key. + // The client mints its delegations by calling the II canister, so its agent + // needs the network's root key to verify the responses. const client = new AuthClient({ - identityProvider: isLocalEnv - ? "http://id.ai.localhost:8000/authorize" - : "https://id.ai/authorize", - ...(isLocalEnv - ? { storage: new LocalStorage(), keyType: "Ed25519" as const } - : {}), + identityProvider: { + authorizeUrl: isLocalEnv + ? "http://id.ai.localhost:8000/authorize" + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey }, + }); + // Leave the signed-in views when the session ends, including from another tab. + client.subscribe(() => { + if (!client.isAuthenticated()) void logout(); }); if (client.isAuthenticated()) { await authenticate(client); @@ -80,6 +85,11 @@ export async function logout() { const currentAuth = get(auth); if (currentAuth.state === "initialized") { + // Switch first so the session subscription does not sign out twice. + auth.update(() => ({ + state: "anonymous", + client: currentAuth.client, + })); // Best-effort: drop cached derived key material so a persisted // (IndexedDB) handle can no longer be used to decrypt after logout. This // must not block sign-out if IndexedDB is unavailable (private mode, @@ -90,17 +100,11 @@ export async function logout() { console.error("Failed to clear derived-key cache on logout:", e); } await currentAuth.client.signOut(); - auth.update(() => ({ - state: "anonymous", - client: currentAuth.client, - })); await replace("/"); } } export async function authenticate(client: AuthClient) { - void handleSessionTimeout(client); - try { const identity = await client.getIdentity(); const passwordManager = await createPasswordManager(identity); @@ -118,22 +122,3 @@ export async function authenticate(client: AuthClient) { })); } } - -// set a timer when the II session will expire and log the user out -async function handleSessionTimeout(client: AuthClient) { - try { - const identity = await client.getIdentity(); - if (!(identity instanceof DelegationIdentity)) return; - - const chain = identity.getDelegation(); - // expiration is a BigInt of nanoseconds since epoch - const expirationMs = - Number(chain.delegations[0].delegation.expiration) / 1_000_000; - - setTimeout(() => { - void logout(); - }, expirationMs - Date.now()); - } catch { - console.error("Could not handle delegation expiry."); - } -} diff --git a/rust/vetkeys/password_manager_with_metadata/icp.yaml b/rust/vetkeys/password_manager_with_metadata/icp.yaml index e5fb6a9169..f529bf0ad3 100644 --- a/rust/vetkeys/password_manager_with_metadata/icp.yaml +++ b/rust/vetkeys/password_manager_with_metadata/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" configuration: candid: backend/backend.did init_args: diff --git a/rust/who_am_i/README.md b/rust/who_am_i/README.md index 1277321bcc..7c125336fa 100644 --- a/rust/who_am_i/README.md +++ b/rust/who_am_i/README.md @@ -33,6 +33,8 @@ icp network start -d icp deploy ``` +> Internet Identity sign-in runs against the Internet Identity canister deployed on the local network (`ii: true` in `icp.yaml`). If signing in fails, update the local network launcher with `icp network update` and restart the network. + The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: ```bash diff --git a/rust/who_am_i/icp.yaml b/rust/who_am_i/icp.yaml index 5c17a9edaf..86cad02a2c 100644 --- a/rust/who_am_i/icp.yaml +++ b/rust/who_am_i/icp.yaml @@ -6,7 +6,7 @@ networks: canisters: - name: backend recipe: - type: "@dfinity/rust@v3.2.0" + type: "@dfinity/rust@v3.4.0" configuration: package: backend candid: src/backend/backend.did diff --git a/rust/who_am_i/src/frontend/package.json b/rust/who_am_i/src/frontend/package.json index 412b87e6d0..d4df8d9d58 100644 --- a/rust/who_am_i/src/frontend/package.json +++ b/rust/who_am_i/src/frontend/package.json @@ -8,13 +8,13 @@ "dev": "vite" }, "dependencies": { - "@icp-sdk/auth": "~5.0.0", - "@icp-sdk/core": "~5.2.0", + "@icp-sdk/auth": "~10.0.0", + "@icp-sdk/core": "~6.1.0", "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@icp-sdk/bindgen": "~0.3.0", + "@icp-sdk/bindgen": "~0.4.1", "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "@vitejs/plugin-react": "4.3.3", diff --git a/rust/who_am_i/src/frontend/src/App.jsx b/rust/who_am_i/src/frontend/src/App.jsx index 08af5ce2e0..7564430b8b 100644 --- a/rust/who_am_i/src/frontend/src/App.jsx +++ b/rust/who_am_i/src/frontend/src/App.jsx @@ -1,61 +1,35 @@ import React, { useState, useEffect } from 'react'; -import { AuthClient } from '@icp-sdk/auth/client'; -import { createBackendActor, identityProviderUrl } from './actor'; +import { authClient, createBackendActor } from './actor'; // Reusable button component const Button = ({ onClick, children }) => ; const App = () => { - const [state, setState] = useState({ - actor: undefined, - authClient: undefined, - isAuthenticated: false, - principal: 'Click "Whoami" to see your principal ID' - }); + const [isAuthenticated, setIsAuthenticated] = useState(authClient.isAuthenticated()); + const [principal, setPrincipal] = useState('Click "Whoami" to see your principal ID'); - // Initialize auth client - useEffect(() => { - updateActor(); - }, []); - - const updateActor = async () => { - const authClient = await AuthClient.create(); - const identity = authClient.getIdentity(); - const actor = createBackendActor(identity); - const isAuthenticated = await authClient.isAuthenticated(); - - setState((prev) => ({ - ...prev, - actor, - authClient, - isAuthenticated - })); - }; + // Track the sign-in status, including changes made in another tab. + useEffect(() => authClient.subscribe(() => setIsAuthenticated(authClient.isAuthenticated())), []); const login = async () => { - await state.authClient.login({ - identityProvider: identityProviderUrl, - onSuccess: updateActor - }); + try { + await authClient.signIn(); + } catch (error) { + console.error('Sign-in failed:', error); + } }; const logout = async () => { - await state.authClient.logout(); - updateActor(); + await authClient.signOut(); }; const whoami = async () => { - setState((prev) => ({ - ...prev, - principal: 'Loading...' - })); + setPrincipal('Loading...'); - const result = await state.actor.whoami(); - const principal = result.toString(); - setState((prev) => ({ - ...prev, - principal - })); + // Read the identity at call time: it is installed only once signIn() completes. + const identity = authClient.isAuthenticated() ? await authClient.getIdentity() : undefined; + const result = await createBackendActor(identity).whoami(); + setPrincipal(result.toString()); }; return ( @@ -82,7 +56,7 @@ const App = () => { - {!state.isAuthenticated ? ( + {!isAuthenticated ? ( ) : ( @@ -90,10 +64,10 @@ const App = () => { - {state.principal && ( + {principal && (

Your principal ID is:

-

{state.principal}

+

{principal}

)} diff --git a/rust/who_am_i/src/frontend/src/actor.js b/rust/who_am_i/src/frontend/src/actor.js index e3a4d83306..6994e2f861 100644 --- a/rust/who_am_i/src/frontend/src/actor.js +++ b/rust/who_am_i/src/frontend/src/actor.js @@ -1,3 +1,4 @@ +import { AuthClient } from "@icp-sdk/auth/client"; import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; import { createActor } from "./bindings/backend"; @@ -16,19 +17,26 @@ const agentOptions = { rootKey: canisterEnv?.IC_ROOT_KEY, }; -// Resolve Internet Identity provider URL. -// II is always deployed on the local network (not the dev server). +// Internet Identity is deployed on the local network (`ii: true` in icp.yaml). // REPLICA_PORT is injected by vite.config.js during `vite dev` since // window.location.port would be the dev server port, not the network port. const isLocal = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.endsWith(".localhost"); -const II_CANISTER_ID = "uqzsh-gqaaa-aaaaq-qaada-cai"; const networkPort = process.env.REPLICA_PORT || window.location.port; -export const identityProviderUrl = isLocal - ? `http://${II_CANISTER_ID}.localhost:${networkPort}` - : "https://id.ai"; + +// The client mints its delegations by calling the II canister, so its agent +// needs the network's root key to verify the responses. +export const authClient = new AuthClient({ + identityProvider: { + authorizeUrl: isLocal + ? `http://id.ai.localhost:${networkPort}/authorize` + : "https://id.ai/authorize", + canisterId: "rdmx6-jaaaa-aaaaa-aaadq-cai", + }, + agentOptions: { rootKey: canisterEnv?.IC_ROOT_KEY }, +}); export function createBackendActor(identity) { return createActor(canisterId, { diff --git a/rust/x509/icp.yaml b/rust/x509/icp.yaml index 4b8e7e5601..2fd52c7486 100644 --- a/rust/x509/icp.yaml +++ b/rust/x509/icp.yaml @@ -1,7 +1,7 @@ canisters: - name: backend recipe: - type: "@dfinity/rust@v3.3.0" + type: "@dfinity/rust@v3.4.0" # test_key_1 works on both the local network and mainnet (test key). # Use key_1 for the production key on mainnet. init_args: '(variant { Ed25519 = "test_key_1" })'