diff --git a/demos/using-dev-build/README.md b/demos/using-dev-build/README.md index 3d91795dec..802354d3a3 100644 --- a/demos/using-dev-build/README.md +++ b/demos/using-dev-build/README.md @@ -27,10 +27,46 @@ At this point, the replica (for all practical matters, a local version of the In }; }; ``` - On the IC, principals are basically the "identity" of someone performing a request or "call" (hence "caller"), and every call must be authenticated — i.e., must have a valid principal. When using Internet Identity you are using [self-authenticating principals](https://smartcontracts.org/docs/interface-spec/index.html#principal), which is a very fancy way of saying that you have a private key on your laptop (hidden behind TouchID, Windows Hello, etc) that your browser uses to sign and prove that you are indeed the person issuing the calls to the IC. + On the IC, a principal is the identifier of someone performing a request or "call" (hence "caller"). Every call must have a valid principal. There is also a special principal for anonymous calls. When using Internet Identity you are using [self-authenticating principals](https://smartcontracts.org/docs/interface-spec/index.html#principal), which is a very fancy way of saying that you have a private key on your laptop (hidden behind TouchID, Windows Hello, etc) that your browser uses to sign and prove that you are indeed the person issuing the calls to the IC. If the IC actually lets the call (request) through to the `whoami` canister, it means that everything checked out, and the `whoami` canister just responds with the information the IC adds to requests, namely your identity (principal). +### Using the Auth-Client Library To Log In With Internet Identity + +DFINITY provides an [easy-to-use library (agent-js)](https://github.com/dfinity/agent-js) to log in with Internet Identity. + +These are the steps required to log in and use the obtained identity for canister calls: +``` +// First we have to create and AuthClient. +const authClient = await AuthClient.create(); + +// Call authClient.login(...) to login with Internet Identity. This will open a new tab +// with the login prompt. The code has to wait for the login process to complete. +// We can either use the callback functions directly or wrap in a promise. +await new Promise((resolve, reject) => { + authClient.login({ + onSuccess: resolve, + onError: reject, + }); +}); +``` +Once the user has been authenticated with Internet Identity we have access to the identity: +``` +// Get the identity from the auth client: +const identity = authClient.getIdentity(); +// Using the identity obtained from the auth client, we can create an agent to interact with the IC. +const agent = new HttpAgent({ identity }); +// Using the interface description of our webapp, we create an Actor that we use to call the service methods. +const webapp = Actor.createActor(webapp_idl, { + agent, + canisterId: webapp_id, +}); +// Call whoami which returns the principal (user id) of the current user. +const principal = await webapp.whoami(); +``` +See [`index.js`](./webapp/index.js) for the full working example. +A detailed description of what happens behind the scenes is available in the [client auth protocol specification](https://github.com/dfinity/internet-identity/blob/main/docs/internet-identity-spec.adoc#client-auth-protocol). + ### Getting the Canister IDs Let's now use those canisters. Don't care about details? Skip to the [helpers](#helpers). diff --git a/demos/using-dev-build/webapp/index.js b/demos/using-dev-build/webapp/index.js index f46b8c6a88..1c5b8e7522 100644 --- a/demos/using-dev-build/webapp/index.js +++ b/demos/using-dev-build/webapp/index.js @@ -17,22 +17,28 @@ export const init = ({ IDL }) => { // Autofills the for the II Url to point to the correct canister. document.body.onload = () => { - const testnetII = - process.env.DFX_NETWORK == "local" - ? `http://localhost:8000/?canisterId=${process.env.II_CANISTER_ID}` - : process.env.DFX_NETWORK == "ic" - ? `https://${process.env.II_CANISTER_ID}.ic0.app` - : `https://${process.env.II_CANISTER_ID}.dfinity.network`; - document.getElementById("iiUrl").value = testnetII; + let iiUrl; + if (process.env.DFX_NETWORK === "local") { + iiUrl = `http://localhost:8000/?canisterId=${process.env.II_CANISTER_ID}`; + } else if (process.env.DFX_NETWORK === "ic") { + iiUrl = `https://${process.env.II_CANISTER_ID}.ic0.app`; + } else { + iiUrl = `https://${process.env.II_CANISTER_ID}.dfinity.network`; + } + document.getElementById("iiUrl").value = iiUrl; }; document.getElementById("loginBtn").addEventListener("click", async () => { - // When the user clicks, we let agent-js do its thing and redirect open an II - // tab for authentication - const iiUrl = document.getElementById("iiUrl").value; + // When the user clicks, we start the login process. + // First we have to create and AuthClient. const authClient = await AuthClient.create(); - // This API is just weird + // Find out which URL should be used for login. + const iiUrl = document.getElementById("iiUrl").value; + + // Call authClient.login(...) to login with Internet Identity. This will open a new tab + // with the login prompt. The code has to wait for the login process to complete. + // We can either use the callback functions directly or wrap in a promise. await new Promise((resolve, reject) => { authClient.login({ identityProvider: iiUrl, @@ -41,14 +47,17 @@ document.getElementById("loginBtn").addEventListener("click", async () => { }); }); - // At this point, we're authenticated with II and we can query the whoami canister + // At this point we're authenticated, and we can get the identity from the auth client: const identity = authClient.getIdentity(); + // Using the identity obtained from the auth client, we can create an agent to interact with the IC. const agent = new HttpAgent({ identity }); + // Using the interface description of our webapp, we create an actor that we use to call the service methods. const webapp = Actor.createActor(webapp_idl, { agent, canisterId: webapp_id, }); - const whoAmI = await webapp.whoami(); - - document.getElementById("loginStatus").innerText = whoAmI.toText(); + // Call whoami which returns the principal (user id) of the current user. + const principal = await webapp.whoami(); + // show the principal on the page + document.getElementById("loginStatus").innerText = principal.toText(); });