ic-auth
Version:
A simple, modular package for integrating Internet Computer authentication providers into your app.
233 lines (232 loc) • 9.38 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateAnonAgent = exports.CreateActor = exports.IdentityLogin = exports.NFIDLogin = exports.PlugLogin = exports.StoicLogin = void 0;
const principal_1 = require("@dfinity/principal");
const agent_1 = require("@dfinity/agent");
const auth_client_1 = require("@dfinity/auth-client");
//@ts-ignore
const ic_stoic_identity_1 = require("ic-stoic-identity");
// Helpers
const shouldFetchRootKey = (host) => {
return !(host.includes('ic0.app') || host.includes('icp0.io'));
};
// A simple Stoic login flow with simplified return data.
// Todo: Stoic is giving a cookies error, need to wait for a response from the stoic team.
/**
* Authenticate the user with the Stoic Wallet provider and return a connected UserObject.
*
* This flow checks if Stoic is already connected, otherwise prompts the user to connect.
* If successful, it creates a new Agent tied to the identity and returns the principal and agent.
*
* @param host - The IC replica host to connect to (e.g., local or mainnet).
* @returns A Promise resolving to a UserObject containing principal, agent, and provider info.
* @throws If Stoic identity cannot be loaded or connection fails.
*
* @todo Stoic is currently known to throw a cookie-related error in some browsers.
* This may be fixed in a later version.
*/
const StoicLogin = async (host) => {
// Checks to see if stoic is already connected or not, then prompts.
let identity = await ic_stoic_identity_1.StoicIdentity.load();
if (!identity) {
identity = await ic_stoic_identity_1.StoicIdentity.connect();
}
if (!identity) {
throw new Error("Stoic Identity not found or connection failed.");
}
const agent = await agent_1.HttpAgent.create({
identity: identity,
host: host,
shouldFetchRootKey: shouldFetchRootKey(host)
});
const principal = identity.getPrincipal().toText();
const returnObject = {
principal: principal,
agent: agent,
provider: "Stoic"
};
console.log("Connected!");
console.log(returnObject);
return returnObject;
};
exports.StoicLogin = StoicLogin;
// Full featured Plug wallet login with simplified return data.
/**
* Logs in with Plug Wallet and returns the authenticated user's agent and information.
*
* @param whitelist - An array of canister IDs the app will access using Plug Wallet.
* @param host - The URL of the Internet Computer replica to connect to.
* Use "https://icp0.io" or "https://ic0.app" for mainnet or "http://127.0.0.1:<YourDFXPort>" for local development.
* @returns A Promise that resolves to a UserObject containing the agent, principal, and provider name.
*/
const PlugLogin = async (whitelist, host) => {
const isConnected = await window.ic.plug.isConnected();
if (isConnected) {
await window.ic.plug.createAgent({ whitelist, host });
const agent = window.ic.plug.agent;
const principal = (await agent.getPrincipal()).toText();
const returnObject = {
principal: principal,
agent: agent,
provider: "Plug"
};
console.log("Connected!");
console.log(returnObject);
return returnObject;
}
else {
await window.ic.plug.requestConnect({ whitelist, host });
const agent = window.ic.plug.agent;
const principal = (await agent.getPrincipal()).toText();
const returnObject = {
principal: principal,
agent: agent,
provider: "Plug"
};
console.log("Connected!");
console.log(returnObject);
return returnObject;
}
};
exports.PlugLogin = PlugLogin;
// A full featured NFID login flow with modern agent and simplified return data.
/**
* Authenticate the user using NFID and return a connected UserObject.
*
* This flow uses DFINITY's AuthClient with NFID as the identity provider.
* It constructs the NFID authorization URL with application name and logo,
* creates a modern Agent tied to the authenticated identity, and resolves the user details.
*
* @param host - The IC replica host to connect to (mainnet or local).
* @returns A Promise resolving to a UserObject containing principal, agent, and provider info.
* @throws If creating the AuthClient or login flow fails.
*/
const NFIDLogin = async (host) => {
return new Promise(async (resolve, reject) => {
const appName = "wallet-testing";
const appLogo = "https://nfid.one/icons/favicon-96x96.png";
const authUrl = `https://nfid.one/authenticate/?applicationName=${appName}&applicationLogo=${appLogo}#authorize`;
let userObject = {
principal: "Not Connected.",
agent: undefined,
provider: "N/A",
};
try {
const authClient = await auth_client_1.AuthClient.create();
await authClient.login({
identityProvider: authUrl,
onSuccess: async () => {
const identity = authClient.getIdentity();
const agent = await agent_1.HttpAgent.create({
identity,
host,
shouldFetchRootKey: shouldFetchRootKey(host),
});
userObject = {
principal: principal_1.Principal.from(identity.getPrincipal()).toText(),
agent,
provider: "NFID",
};
console.log("Connected!");
console.log(userObject);
resolve(userObject);
},
onError: (error) => {
console.error("NFID Login Failed:", error);
reject(error);
},
});
}
catch (error) {
console.error("Error creating AuthClient:", error);
reject(error);
}
});
};
exports.NFIDLogin = NFIDLogin;
// A fully featured Internet Identity login flow with simplified return data.
/**
* Authenticate the user using Internet Identity and return a connected UserObject.
*
* This flow uses DFINITY's AuthClient to open the Internet Identity login,
* creates an Agent with the returned identity, and resolves the user details.
* It handles both mainnet and local environments by conditionally fetching the root key.
*
* @param host - The IC replica host to connect to (mainnet or local).
* @returns A Promise resolving to a UserObject containing principal, agent, and provider info.
* @throws If creating the AuthClient or login flow fails.
*/
const IdentityLogin = async (host) => {
return new Promise(async (resolve, reject) => {
let identity;
let userObject = {
principal: "Not Connected.",
agent: undefined,
provider: "N/A",
};
try {
const authClient = await auth_client_1.AuthClient.create();
await authClient.login({
identityProvider: "https://identity.ic0.app",
onSuccess: async () => {
identity = authClient.getIdentity();
const agent = await agent_1.HttpAgent.create({
identity: identity,
host: host,
shouldFetchRootKey: shouldFetchRootKey(host),
});
userObject = {
principal: principal_1.Principal.from(identity.getPrincipal()).toText(),
agent: agent,
provider: "Internet Identity",
};
console.log("Connected!");
console.log(userObject);
resolve(userObject);
},
onError: async (error) => {
userObject = {
principal: "Not Connected.",
agent: undefined,
provider: "N/A",
};
console.log("Error Logging In");
reject(error);
},
});
}
catch (error) {
console.error("Error creating AuthClient:", error);
reject(error);
}
});
};
exports.IdentityLogin = IdentityLogin;
/**
* Create an actor for any canister using a provided agent.
* @param agent - The authenticated or anonymous Agent instance.
* @param idl - The IDL factory for the target canister.
* @param canisterId - The canister ID to connect to.
* @returns A typed Actor subclass for the canister.
*/
const CreateActor = async (agent, idl, canisterId) => {
const actor = agent_1.Actor.createActor(idl, {
agent,
canisterId,
});
return actor;
};
exports.CreateActor = CreateActor;
/**
* Create an anonymous agent for public queries or read-only calls.
* @param host - Optional IC replica host (defaults to mainnet).
* @returns An Agent instance with no identity attached.
*/
const CreateAnonAgent = async (host) => {
const agent = await agent_1.HttpAgent.create({
host,
shouldFetchRootKey: shouldFetchRootKey(host),
});
return agent;
};
exports.CreateAnonAgent = CreateAnonAgent;