Welcome to IC-Auth! The easiest way to integrate Plug, Stoic, Internet Identity, and NFID authentication for your Internet Computer apps.
IC-Auth is a lightweight, modular TypeScript package that helps developers plug wallet authentication directly into their DFINITY dapps.
It gives you simple, type-safe helpers for the most common IC wallets, so you can focus on your frontend and canister logic to get up and running quickly.
- Plug Wallet
- Internet Identity
- NFID
- Stoic
- Stoic: A known issue with cookie storage affects Stoic logins in some browsers. This will be addressed in a future Stoic release.
- NFID: Supports anonymous mode only for now β so canister calls work, but payments and session delegation are limited. This will be expanded soon.
- Fully modernized: Uses latest DFINITY agent APIs (
Agent
instead ofHttpAgent
). - Dependencies updated to latest stable versions.
- No more embedded frontend β the package is framework-agnostic.
- Cleaner exports:
UserObject
type is inline. - Local dev now supported for all providers via
host
parameter. - Removed legacy
hello
canister and embedded assets. - Designed to pair cleanly with any custom canister IDL.
npm install ic-auth
These steps are for creating your own simple login UI/UX using the modular functions. A more advanced design will be shown below.
Import the login functions you want and the universal UserObject
type:
import { PlugLogin, StoicLogin, NFIDLogin, IdentityLogin, CreateActor, UserObject } from "ic-auth";
Create a function to trigger the login and catch the data afterwards. If you're using Plug, it requires a list of canister addresses that you plan to make calls to. This is only required for Plug so we will show that here.
You will also need to define the host URL that the authentication will be looking towards for login. Again, if not using Plug you only need to toss the host as a string.
const canisterID = "oyjva-2yaaa-aaaam-qbaya-cai";
const whitelist = [canisterID];
const host = "https://icp0.io" // "https://localhost:XXXX" for local dfx instances.
const handleLogin = async() => {
const userObject = await PlugLogin(whitelist, host);
console.log(userObject);
// Handle code will go here...
}
Take the login handler and attach it to a UI element of your choice.
<button onClick={handleLogin}>Login</button>
After a successful login you should receive the UserObject
, which looks like this:
type UserObject = {
principal: string,
agent: Agent | undefined,
provider: string
}
Reminder: You can import this specific type by adding UserObject
into your imports directly from ic-auth
.
The UserObject
can be used to create an actor for canister calls, display the user's principal address, or trigger code depending on the provider chosen. This next example shows how to create an actor using the CreateActor
function.
To create an actor you will need to pass in the canister address you wish to call, the associated canister interface description language (IDL) file, and the agent from the UserObject. You can generate the interfaces folder by running dfx generate
after building your backend canister, then import from that folder.
import { PlugLogin, StoicLogin, NFIDLogin, IdentityLogin, UserObject, CreateActor } from 'ic-auth';
import { idlFactory as YourIDL } from "./interfaces/your_canister";
const canisterID = "oyjva-2yaaa-aaaam-qbaya-cai";
const whitelist = [canisterID];
const host = "https://icp0.io"; // or your local dev host
const handleLogin = async() => {
const userObject = await PlugLogin(whitelist, host);
console.log(userObject);
const actor = await CreateActor(userObject.agent!, YourIDL, canisterID);
// Handle code will go here...
}
Now you can style the elements, add more providers, or continue on to see a more complex and full featured example.
This example will bring you through the steps of creating a multi-wallet supported login menu.
import { PlugLogin, StoicLogin, NFIDLogin, IdentityLogin, UserObject, CreateActor } from 'ic-auth';
const canisterID = "oyjva-2yaaa-aaaam-qbaya-cai";
const whitelist = [canisterID];
const host = "https://icp0.io"; // or your local dev host
const handleLogin = async (provider: string) => {
let user: UserObject = {
principal: "Not Connected.",
agent: undefined,
provider: "N/A"
};
if (provider === "Plug") {
user = await PlugLogin(whitelist, host);
} else if (provider === "Stoic") {
user = await StoicLogin(host);
} else if (provider === "NFID") {
user = await NFIDLogin(host);
} else if (provider === "Identity") {
user = await IdentityLogin(host);
}
console.log(user);
const actor = await CreateActor(user.agent!, YourIDL, canisterID);
// Interact with your canister here
};
<div class="wallet-buttons">
<button onclick="handleLogin('Plug')">Plug</button>
<button onclick="handleLogin('Stoic')">Stoic</button>
<button onclick="handleLogin('NFID')">NFID</button>
<button onclick="handleLogin('Identity')">Internet Identity</button>
</div>
- π Plug Wallet: plugwallet.ooo
- π NFID: nfid.one
- π§ Stoic Wallet: stoicwallet.com
- ποΈ Internet Identity: internetcomputer.org/internet-identity
- π§© Internet Computer Docs (AI Powered): internetcomputer.org/docs/home/
- π Mainnet Canisters: DFINITY Forum
Author: Daniel McCoy
Twitter: @RealDanMcCoy
Enjoy building on the Internet Computer π