{"id":13523387,"url":"https://github.com/kristoferlund/ic-use-internet-identity","last_synced_at":"2025-12-26T18:07:13.070Z","repository":{"id":217753688,"uuid":"744727951","full_name":"kristoferlund/ic-use-internet-identity","owner":"kristoferlund","description":"Hook that makes it easy to integrate IC Internet Identity into your React application","archived":false,"fork":false,"pushed_at":"2025-01-07T21:38:36.000Z","size":251,"stargazers_count":12,"open_issues_count":0,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T07:07:07.420Z","etag":null,"topics":["dfinity","hook","internetcomputer","react"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/ic-use-internet-identity","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kristoferlund.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-17T22:11:32.000Z","updated_at":"2025-01-07T21:36:59.000Z","dependencies_parsed_at":"2024-01-18T05:51:05.889Z","dependency_job_id":"54b87b50-7250-4dbc-8db9-a7b68e31e7f4","html_url":"https://github.com/kristoferlund/ic-use-internet-identity","commit_stats":null,"previous_names":["kristoferlund/ic-use-internet-identity"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kristoferlund%2Fic-use-internet-identity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kristoferlund%2Fic-use-internet-identity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kristoferlund%2Fic-use-internet-identity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kristoferlund%2Fic-use-internet-identity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kristoferlund","download_url":"https://codeload.github.com/kristoferlund/ic-use-internet-identity/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248166927,"owners_count":21058480,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dfinity","hook","internetcomputer","react"],"created_at":"2024-08-01T06:00:59.576Z","updated_at":"2025-12-26T18:07:13.043Z","avatar_url":"https://github.com/kristoferlund.png","language":"TypeScript","funding_links":[],"categories":["Client Libraries (Agents)"],"sub_categories":["JavaScript/TypeScript"],"readme":"# ic-use-internet-identity\n\n[Internet Identity](https://internetcomputer.org/how-it-works/web-authentication-identity) is an authentication service running on the [Internet Computer](https://internetcomputer.org). It allows users to create an identity that can be used to authenticate with canisters (smart contracts) running on the Internet Computer.\n\n`ic-use-internet-identity` is a hook that makes it easy to integrate Internet Identity into your React application. It provides a simple interface for logging in and out with the Internet Identity service.\n\n[![version][version-image]][npm-link]\n[![downloads][dl-image]][npm-link]\n\n## Features\n\n- **Cached Identity**: The identity is cached in local storage and restored on page load. This allows the user to stay logged in even if the page is refreshed.\n- **Login progress**: State variables are provided to indicate whether the user is logged in, logging in, or logged out.\n- **Reactive Identity Expiry**: Automatically resets authentication state when the identity expires, keeping your app in sync without page reloads.\n- **Works with ic-use-actor**: Plays nicely with [ic-use-actor](https://www.npmjs.com/package/ic-use-actor) that provides easy access to canister methods.\n- **Router integration**: Exposes `ensureInitialized()` and `isAuthenticated()` for use outside React (examples use TanStack Router).\n\n## Table of Contents\n\n- [ic-use-internet-identity](#ic-use-internet-identity)\n  - [Features](#features)\n  - [Table of Contents](#table-of-contents)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Prerequisites](#prerequisites)\n    - [1. Setup the `InternetIdentityProvider` component](#1-setup-the-internetidentityprovider-component)\n    - [2. Connect the `login()` function to a button](#2-connect-the-login-function-to-a-button)\n    - [Monitoring the Login Process](#monitoring-the-login-process)\n    - [Status Helper Properties](#status-helper-properties)\n    - [3. Use the `identity` context variable to access the identity](#3-use-the-identity-context-variable-to-access-the-identity)\n  - [InternetIdentityProvider props](#internetidentityprovider-props)\n  - [LoginOptions](#loginoptions)\n  - [useInternetIdentity interface](#useinternetidentity-interface)\n  - [Error Handling](#error-handling)\n  - [Router integration](#router-integration)\n    - [Available Functions](#available-functions)\n    - [Basic Example](#basic-example)\n    - [Client-side (reactive) Auth Guard](#client-side-reactive-auth-guard)\n    - [Creating a Route Guard Helper](#creating-a-route-guard-helper)\n    - [Important Notes](#important-notes)\n  - [Security Considerations](#security-considerations)\n  - [Updates](#updates)\n  - [Author](#author)\n  - [Contributing](#contributing)\n  - [License](#license)\n\n## Installation\n\n```bash\npnpm install ic-use-internet-identity\n```\n\nThe hook also requires the following `@icp-sdk/x` packages to be installed with a version of at least `v5`:\n\n```bash\npnpm install @icp-sdk/core @icp-sdk/auth\n```\n\n## Usage\n\n\u003e [!TIP]\n\u003e For a complete example, see the [ic-use-internet-identity-demo](https://github.com/kristoferlund/ic-use-internet-identity-demo) demo project.\n\nTo use `ic-use-internet-identity` in your React application, follow these steps:\n\n### 1. Setup the `InternetIdentityProvider` component\n\nWrap your application's root component with `InternetIdentityProvider` to provide all child components access to the identity context.\n\n```jsx\n// main.tsx\n\nimport { InternetIdentityProvider } from \"ic-use-internet-identity\";\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\n\nReactDOM.createRoot(document.getElementById(\"root\")!).render(\n  \u003cReact.StrictMode\u003e\n    \u003cInternetIdentityProvider\u003e\n      \u003cApp /\u003e\n    \u003c/InternetIdentityProvider\u003e\n  \u003c/React.StrictMode\u003e\n);\n```\n\n\u003e [!TIP]\n\u003e **Identity Provider Configuration**: The library defaults to using the main Internet Identity instance at `https://identity.ic0.app`. You can override this by setting the `identityProvider` in your `loginOptions`.\n\u003e\n\u003e - **Default**: `https://identity.ic0.app` (used automatically)\n\u003e - **Custom via loginOptions**: Pass `identityProvider` in `loginOptions` prop\n\u003e - **Local development**: `http://${CANISTER_ID_INTERNET_IDENTITY}.localhost:4943`\n\u003e\n\u003e **Configure via loginOptions**\n\u003e ```tsx\n\u003e \u003cInternetIdentityProvider\n\u003e   loginOptions={{\n\u003e     identityProvider: process.env.DFX_NETWORK === \"local\"\n\u003e       ? `http://${process.env.CANISTER_ID_INTERNET_IDENTITY}.localhost:4943`\n\u003e       : \"https://identity.ic0.app\"\n\u003e   }}\n\u003e \u003e\n\u003e   \u003cApp /\u003e\n\u003e \u003c/InternetIdentityProvider\u003e\n\u003e ```\n\n### 2. Connect the `login()` function to a button\n\nThe `login()` function initiates the Internet Identity authentication process. Here's what happens when you call it:\n\n1. **Pre-flight Validation**: The function first validates that all prerequisites are met (provider is present, auth client is initialized, user isn't already authenticated)\n2. **Popup Window**: If validation passes, it opens the Internet Identity service in a new popup window\n3. **Status Updates**: The `status` immediately changes to `\"logging-in\"` and remains there until the process completes\n4. **User Authentication**: The user completes authentication in the popup window\n5. **Result Handling**:\n   - **Success**: `status` becomes `\"success\"`, `identity` is populated, and the popup closes\n   - **Error**: `status` becomes `\"error\"` and `error` contains the error details\n   - **User Cancellation**: Treated as an error with appropriate error message\n\n\u003e [!WARNING]\n\u003e **User Interaction Required**: The `login()` function MUST be called in response to a user interaction (e.g., button click). Calling it in `useEffect` or similar will fail because browsers block popup windows that aren't triggered by user actions.\n\n\u003e [!IMPORTANT]\n\u003e **No Promise Handling Required**: The `login()` function returns `void` and handles all results through the hook's state. Monitor the `status`, `error`, and `identity` values returned by the hook instead of using try/catch blocks.\n\n#### Monitoring the Login Process\n\nThe login process follows a predictable status flow:\n\n- **`\"initializing\"`** → Library is loading and checking for existing authentication\n- **`\"idle\"`** → Ready to login\n- **`\"logging-in\"`** → Login popup is open, user is authenticating\n- **`\"success\"`** → Login completed successfully, `identity` is available\n- **`\"error\"`** → Login failed, check `error` for details\n\nUse the `status` and `error` state variables to track the login process and provide appropriate UI feedback:\n\n```jsx\n// LoginButton.tsx\n\nimport { useInternetIdentity } from \"ic-use-internet-identity\";\n\nexport function LoginButton() {\n  const { login, status, error, isError, identity } = useInternetIdentity();\n\n  const renderButton = () =\u003e {\n    switch (status) {\n      case \"initializing\":\n        return (\n          \u003cbutton disabled\u003e\n            ⏳ Initializing...\n          \u003c/button\u003e\n        );\n      case \"idle\":\n        return (\n          \u003cbutton onClick={login}\u003e\n            Login with Internet Identity\n          \u003c/button\u003e\n        );\n      case \"logging-in\":\n        return (\n          \u003cbutton disabled\u003e\n            🔄 Logging in...\n          \u003c/button\u003e\n        );\n      case \"success\":\n        return (\n          \u003cbutton disabled\u003e\n            ✅ Logged in as {identity?.getPrincipal().toString().slice(0, 8)}...\n          \u003c/button\u003e\n        );\n      case \"error\":\n        return (\n          \u003cbutton onClick={login}\u003e\n            🔄 Retry Login\n          \u003c/button\u003e\n        );\n      default:\n        return null;\n    }\n  };\n\n  return (\n    \u003cdiv\u003e\n      {renderButton()}\n      {isError \u0026\u0026 (\n        \u003cdiv style={{ color: \"red\", marginTop: \"8px\" }}\u003e\n          ❌ Login failed: {error?.message}\n        \u003c/div\u003e\n      )}\n    \u003c/div\u003e\n  );\n}\n```\n\n#### Status Helper Properties\n\nThe hook also provides convenient boolean properties for common status checks:\n\n```jsx\nconst {\n  isInitializing, // status === \"initializing\"\n  isIdle,        // status === \"idle\"\n  isLoggingIn,   // status === \"logging-in\"\n  isLoginSuccess, // status === \"success\"\n  isError        // status === \"error\"\n} = useInternetIdentity();\n\n// Example usage\nif (isInitializing) {\n  // Show initial loading state\n}\n\nif (isLoggingIn) {\n  // Show login spinner\n}\n\nif (isLoginSuccess \u0026\u0026 identity) {\n  // User is authenticated, show protected content\n}\n```\n\n### 3. Use the `identity` context variable to access the identity\n\nThe `identity` context variable contains the identity of the currently logged in user. The identity is available after successfully loading the identity from local storage or completing the login process.\n\nThe preferred way to use the identity is to connect it to the [ic-use-actor](https://www.npmjs.com/package/ic-use-actor) hook. The hook provides a typed interface to the canister methods as well as interceptor functions for handling errors etc.\n\n```jsx\n// Actors.tsx\n\nimport { ReactNode } from \"react\";\nimport {\n  ActorProvider,\n  createActorContext,\n  createUseActorHook,\n} from \"ic-use-actor\";\nimport {\n  canisterId,\n  idlFactory,\n} from \"path-to/your-service/index\";\nimport { _SERVICE } from \"path-to/your-service.did\";\nimport { useInternetIdentity } from \"ic-use-internet-identity\";\n\nconst actorContext = createActorContext\u003c_SERVICE\u003e();\nexport const useActor = createUseActorHook\u003c_SERVICE\u003e(actorContext);\n\n export default function Actors({ children }: { children: ReactNode }) {\n  const { identity } = useInternetIdentity();\n\n  return (\n    \u003cActorProvider\u003c_SERVICE\u003e\n      canisterId={canisterId}\n      context={actorContext}\n      identity={identity}\n      idlFactory={idlFactory}\n    \u003e\n      {children}\n    \u003c/ActorProvider\u003e\n  );\n}\n```\n\n## InternetIdentityProvider props\n\n````ts\n{\n  /** Options for creating the {@link AuthClient}. See AuthClient documentation for list of options\n   *\n   *`ic-use-internet-identity` defaults to disabling the AuthClient idle handling (clearing identities\n   * from store and reloading the window when user is idle). If that behaviour is preferred, set these settings:\n   *\n   * ```\n   * const options = {\n   *   idleOptions: {\n   *     disableDefaultIdleCallback: false,\n   *     disableIdle: false,\n   *   },\n   * }\n   * ```\n   */\n  createOptions?: AuthClientCreateOptions;\n\n  /** Options that determine the behaviour of the {@link AuthClient} login call. These options are a subset of\n   * the {@link AuthClientLoginOptions}. */\n  loginOptions?: LoginOptions;\n\n  /** Clear the identity automatically on expiration. Default value is `true`. */\n  clearIdentityOnExpiry?: boolean;\n\n  /** The child components that the InternetIdentityProvider will wrap. This allows any child\n   * component to access the authentication context provided by the InternetIdentityProvider. */\n  children: ReactNode;\n}\n````\n\n## LoginOptions\n\nThe `LoginOptions` interface extends `AuthClientLoginOptions` from `@icp-sdk/auth/client` with some modifications:\n\n```ts\nimport type { AuthClientLoginOptions } from \"@icp-sdk/auth/client\";\n\nexport interface LoginOptions\n  extends Omit\u003c\n    AuthClientLoginOptions,\n    \"onSuccess\" | \"onError\" | \"maxTimeToLive\"\n  \u003e {\n  /**\n   * Expiration of the authentication in nanoseconds\n   * @default BigInt(3_600_000_000_000) nanoseconds (1 hour)\n   */\n  maxTimeToLive?: bigint;\n}\n```\n\nThis means you can use all properties from `AuthClientLoginOptions` except `onSuccess`, `onError`. Available properties include:\n\n- **`identityProvider?: string | URL`** - Identity provider URL (defaults to `https://identity.ic0.app`)\n- **`maxTimeToLive?: bigint`** - Session expiration (defaults to 1 hour)\n- **`allowPinAuthentication?: boolean`** - Allow PIN/temporary key authentication\n- **`derivationOrigin?: string | URL`** - Origin for delegated identity generation\n- **`windowOpenerFeatures?: string`** - Popup window configuration\n- **`customValues?: Record\u003cstring, unknown\u003e`** - Extra values for login request\n\n## useInternetIdentity interface\n\n```ts\nexport type Status =\n  | \"initializing\"\n  | \"idle\"\n  | \"logging-in\"\n  | \"success\"\n  | \"error\";\n\nexport type InternetIdentityContext = {\n  /** The identity is available after successfully loading the identity from local storage\n   * or completing the login process. */\n  identity?: Identity;\n\n  /** Connect to Internet Identity to login the user. */\n  login: () =\u003e void;\n\n  /** Clears the identity from the state and local storage. Effectively \"logs the user out\". */\n  clear: () =\u003e void;\n\n  /** The status of the login process. Note: The login status is not affected when a stored\n   * identity is loaded on mount. */\n  status: Status;\n\n  /** `status === \"initializing\"` */\n  isInitializing: boolean;\n\n  /** `status === \"idle\"` */\n  isIdle: boolean;\n\n  /** `status === \"logging-in\"` */\n  isLoggingIn: boolean;\n\n  /** `status === \"success\"` */\n  isLoginSuccess: boolean;\n\n  /** `status === \"error\"` */\n  isError: boolean;\n\n  /** Login error. Unsurprisingly. */\n  error?: Error;\n};\n```\n\n## Error Handling\n\nThe library handles all errors through its state management system. You don't need try/catch blocks - simply monitor the `error` and `isError` state:\n\n```tsx\nimport { useInternetIdentity } from \"ic-use-internet-identity\";\n\nexport function LoginComponent() {\n  const { login, error, isError, status } = useInternetIdentity();\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton\n        onClick={login}\n        disabled={status === \"logging-in\"}\n      \u003e\n        {status === \"logging-in\" ? \"Logging in...\" : \"Login\"}\n      \u003c/button\u003e\n\n      {isError \u0026\u0026 (\n        \u003cdiv style={{ color: \"red\" }}\u003e\n          Login error: {error?.message}\n        \u003c/div\u003e\n      )}\n    \u003c/div\u003e\n  );\n}\n```\n\n## Router integration\n\nWhen using `ic-use-internet-identity` with routing libraries (for example, TanStack Router), it's recommended to handle the initialization phase before allowing navigation to protected routes. The library exports utility functions that work outside of React components and can be used with many routing libraries — TanStack Router is shown here as an example.\n\n### Available Functions\n\n```typescript\n// Wait for the identity initialization to complete and get restored identity\nensureInitialized(): Promise\u003cIdentity | undefined\u003e\n\n// Check if user is authenticated \nisAuthenticated(): boolean\n\n// Get the current identity \ngetIdentity(): Identity | undefined\n```\n\n### Basic Example\n\nHere's how to protect routes (example: TanStack Router):\n\n```tsx\nimport { createRoute, redirect } from \"@tanstack/react-router\";\nimport { ensureInitialized, isAuthenticated } from \"ic-use-internet-identity\";\n\n// Protected route example\nconst dashboardRoute = createRoute({\n  getParentRoute: () =\u003e rootRoute,\n  path: \"dashboard\",\n  beforeLoad: async () =\u003e {\n    const identity = await ensureInitialized();\n    if (!identity) {\n      throw redirect({ to: \"/login\" });\n    }\n  },\n  component: DashboardComponent,\n});\n```\n\n### Client-side (reactive) Auth Guard\n\nNote: `beforeLoad` is executed during navigation and does **not** re-run when authentication state changes. If a user signs out after a route has already loaded, the `beforeLoad` hook will not be invoked again. To handle dynamic changes in authentication (for example, user-initiated sign out), provide a React component that observes the hook and reacts to changes at runtime.\n\n```tsx\nimport { useRouter } from \"@tanstack/react-router\";\nimport { useInternetIdentity } from \"ic-use-internet-identity\";\nimport { useEffect } from \"react\";\n\nexport function AuthGuard() {\n  const router = useRouter();\n  const { identity } = useInternetIdentity();\n\n  useEffect(() =\u003e {\n    if (!identity) {\n      void router.invalidate() // This forces beforeLoad to be re-run and user directed to login page\n    }\n  }, [identity, router]);\n\n  return null;\n}\n```\n\n### Creating a Route Guard Helper\n\nFor multiple protected routes you can extract a small `beforeLoad` helper and use file-route helpers (the example below uses TanStack Router). Below are two patterns: a simple `authenticateRoute()` helper and an example showing how to create a protected file route with `createFileRoute`.\n\n```ts\n// authenticateRoute helper function: src/lib/authenticate-route.ts\nimport { isRedirect, redirect } from \"@tanstack/react-router\";\nimport { ensureInitialized } from \"ic-use-internet-identity\";\n\nexport async function authenticateRoute() {\n  try {\n    const identity = await ensureInitialized();\n    if (!identity) {\n      // No identity -\u003e redirect to login\n      // eslint-disable-next-line @typescript-eslint/only-throw-error\n      throw redirect({ to: \"/login\" });\n    }\n    // Additional initialization, authenticate actor, etc.\n  } catch (err) {\n    if (isRedirect(e)) throw e // Re-throw if error is a redirect\n    console.error(\"Identity initialization failed:\", err);\n    // Initialization error — redirect to an error page\n    // eslint-disable-next-line @typescript-eslint/only-throw-error\n    throw redirect({ to: \"/error\" });\n  }\n}\n```\n\n```ts\n// Example file route: src/routes/about.tsx\nimport { createFileRoute } from \"@tanstack/react-router\";\nimport { authenticateRoute } from \"../lib/authenticate-route\";\nimport About from \"../components/About\";\n\nexport const Route = createFileRoute(\"/about\")({\n  beforeLoad: async () =\u003e authenticateRoute(),\n  component: About,\n});\n```\n\n### Important Notes\n\n1. **Always await initialization**: The `ensureInitialized()` function ensures the library has finished checking for cached identities before making routing decisions.\n\n2. **Double-check in components**: `beforeLoad` runs once during navigation and does not react to later authentication changes (for example, when a user signs out). Use the `useInternetIdentity` hook in your components — or the `AuthGuard` component above — to observe auth state changes and perform redirects or show fallback UI.\n\n3. **Handle loading states**: During initialization (\u003c 1 second), consider showing a loading spinner or splash screen.\n\n4. **Redirect patterns**: You can either redirect to a login page or let components handle the unauthenticated state based on your UX preferences.\n\n## Security Considerations\n\n- **Delegation Expiry**: By default, delegations expire after 1 hour and the identity state is automatically reset. Monitor `identity` for changes and handle re-authentication.\n- **Secure Storage**: Identities are stored in browser local storage. Consider the security implications for your use case.\n- **Session Management**: The library automatically clears the identity on expiry by default. To disable, set `clearIdentityOnExpiry={false}` on the `InternetIdentityProvider`. Consider your app's security requirements.\n\n## Updates\n\nSee the [CHANGELOG](CHANGELOG.md) for details on updates.\n\n## Author\n\n- [kristofer@kristoferlund.se](mailto:kristofer@kristoferlund.se)\n- Twitter: [@kristoferlund](https://twitter.com/kristoferlund)\n- Discord: kristoferkristofer\n- Telegram: [@kristoferkristofer](https://t.me/kristoferkristofer)\n\n## Contributing\n\nContributions are welcome. Please submit your pull requests or open issues to propose changes or report bugs.\n\n## License\n\nThis project is licensed under the MIT License. See the LICENSE file for more details.\n\n[version-image]: https://img.shields.io/npm/v/ic-use-internet-identity\n[dl-image]: https://img.shields.io/npm/dw/ic-use-internet-identity\n[npm-link]: https://www.npmjs.com/package/ic-use-internet-identity\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkristoferlund%2Fic-use-internet-identity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkristoferlund%2Fic-use-internet-identity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkristoferlund%2Fic-use-internet-identity/lists"}