You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -31,11 +31,11 @@ Internet Identity (II) is the Internet Computer's native authentication system.
31
31
32
32
2.**Setting delegation expiry too long.** Maximum delegation expiry is 30 days (2_592_000_000_000_000 nanoseconds). Longer values are silently clamped, which causes confusing session behavior. Use 8 hours for normal apps, 30 days maximum for "remember me" flows.
33
33
34
-
3.**Not handling auth callbacks.**The `authClient.login()`call requires `onSuccess` and `onError` callbacks. Without them, login failures are silently swallowed.
34
+
3.**Not awaiting `signIn()` or skipping the `try`/`catch`.**`authClient.signIn()`returns a promise that rejects when the user closes the popup or authentication fails. Without `await` and a `catch`, those failures are silently swallowed.
35
35
36
36
4.**Using `shouldFetchRootKey` or `fetchRootKey()` instead of the `ic_env` cookie.** The `ic_env` cookie (set by the asset canister or the Vite dev server) already contains the root key as `IC_ROOT_KEY`. Pass it via the `rootKey` option to `HttpAgent.create()` — this works in both local and production environments without environment branching. See the icp-cli skill's `references/binding-generation.md` for the pattern. Never call `fetchRootKey()` — it fetches the root key from the replica at runtime, which lets a man-in-the-middle substitute a fake key on mainnet.
37
37
38
-
5.**Getting `2vxsx-fae` as the principal after login.** That is the anonymous principal -- it means authentication silently failed. Common causes: wrong `identityProvider` URL, missing `onSuccess` callback, or not extracting the identity from `authClient.getIdentity()`after login.
38
+
5.**Getting `2vxsx-fae` as the principal after login.** That is the anonymous principal -- it means authentication silently failed. Common causes: wrong `identityProvider` URL passed to the `AuthClient` constructor, an unhandled rejection from `signIn()`, or reading `getIdentity()`before `signIn()` resolved.
39
39
40
40
6.**Passing principal as string to backend.** The `AuthClient` gives you an `Identity` object. Backend canister methods receive the caller principal automatically via the IC protocol -- you do not pass it as a function argument. The caller principal is available on the backend via `shared(msg) { msg.caller }` in Motoko or `ic_cdk::api::msg_caller()` in Rust. For backend access control patterns, see the **canister-security** skill.
41
41
@@ -71,9 +71,6 @@ import { AuthClient } from "@icp-sdk/auth/client";
71
71
import { HttpAgent, Actor } from "@icp-sdk/core/agent";
72
72
import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env";
73
73
74
-
// Module-scoped so login/logout/createAuthenticatedActor can access it.
75
-
let authClient;
76
-
77
74
// Read the ic_env cookie (set by the asset canister or Vite dev server).
78
75
// Contains the root key and canister IDs — works in both local and production.
79
76
const canisterEnv = safeGetCanisterEnv();
@@ -91,24 +88,26 @@ function getIdentityProviderUrl() {
91
88
return "https://id.ai";
92
89
}
93
90
94
-
// Login
91
+
// Construct once — identityProvider (and optionally derivationOrigin or
92
+
// openIdProvider for one-click sign-in: 'google' | 'apple' | 'microsoft')
93
+
// are configured at construction time, not per sign-in.
94
+
const authClient = new AuthClient({
95
+
identityProvider: getIdentityProviderUrl(),
96
+
});
97
+
98
+
// Login: signIn() returns the new Identity directly and rejects if the user
99
+
// closes the popup or authentication fails.
95
100
async function login() {
96
-
return new Promise((resolve, reject) => {
97
-
authClient.login({
98
-
identityProvider: getIdentityProviderUrl(),
101
+
try {
102
+
const identity = await authClient.signIn({
99
103
maxTimeToLive: BigInt(8) * BigInt(3_600_000_000_000), // 8 hours in nanoseconds
100
-
onSuccess: () => {
101
-
const identity = authClient.getIdentity();
102
-
const principal = identity.getPrincipal().toText();
103
-
console.log("Logged in as:", principal);
104
-
resolve(identity);
105
-
},
106
-
onError: (error) => {
107
-
console.error("Login failed:", error);
108
-
reject(error);
109
-
},
110
104
});
111
-
});
105
+
console.log("Logged in as:", identity.getPrincipal().toText());
106
+
return identity;
107
+
} catch (error) {
108
+
console.error("Login failed:", error);
109
+
throw error;
110
+
}
112
111
}
113
112
114
113
// Logout
@@ -132,12 +131,9 @@ async function createAuthenticatedActor(identity, canisterId, idlFactory) {
132
131
// Initialization — wraps async setup in a function so this code works with
133
132
// any bundler target (Vite defaults to es2020 which lacks top-level await).
0 commit comments