Web authentication workflow for apps without a front-end canister

Hi
We are building a react native app, and I want to implement internet identity for login/register. I can open a window pointing to internet identity, but I am not sure how the return can be fetched in the app without window.listener of web. anyone has a sample or an insight?

From my knowledge, I am going to re-write the whole auth-client using WebView instead of window unless someone has a better approach

I could probably make that happen as a different configuration option for the package - I just need to figure out how to test it

3 Likes

We are experimenting adding a mobile app as a Device to an II.

1 Like

@dpdp
@kpeacock
an you guys elaborate more? I tested with WebView and it seems it is still not supported by II, so not sure how we can go about receiving the postMessage that is triggered by II in react native ? I tested Linking and WebBrowser without luck.

After reading this doc( internet-identity/internet-identity-spec.adoc at main · dfinity/internet-identity (github.com), I am going to try the following:

1- Create a simple html page with iframe pointing to Internet Identity
2- Create a redirect to my app with corresponding parameter to identify status after receving postMessage response from II
3- open this with WebBrowser in app and decode the returned parameters.

Yes, iframe in a webview was how we expected Internet Identity to work for mobile. I haven’t personally done a proof of concept yet though, so I was hesitant to try it. Also, I’m not sure if the certified assets will still be a problem in that workflow, so I was hesitant to recommend it.

I tried this approach:
1- Opened a custom webpage from the app
2- The custom page has a login link
3- When login link is clicked, it opens Internet Identity and gets back the result of login
4- If login is successful it can go back to app with received data

However, the point I am not sure, is that if I have the returned data from a succesful login(such as principal, public key, …) can I still make authenticated calls to canisters somehow from within the app or I need to have the authClient object to do so?

ezgif-2-48b91536cf1f

So the process is this:

-Website generates a key pair to sign with, just any random one
-Website links to II and asks to approve the pub key for the above random key to act as a delegated signer for a specified timeframe (default is 30 mins)

  • You complete the II steps and approve
  • You are returned to the website

To use this delegated signing key you just need the random keypair that was generated. I would probably suggest a slightly different approach though…

  • Generate the key pair in the app (so you don’t need to transmit the private key)
  • Send the pub key to your website to ask to login with II
  • User clicks login on the website (don’t make this automated, make this specifically ask the user to confirm they want to continue)
  • Submit the request to II - you will need to make some custom changes to the auth client but it’s not too hard to do. I had done this but I haven’t open sourced my code, mostly coz it’s dirty AF currently

Once II is confirmed, you can return to app and use the delegated key in app. You will need to generate a delegated signing identity in app though to make sure it works with the agent.

3 Likes

Try copying the DelegationIdentity logic from the source code of the Auth Client. I think you have everything you need

1 Like

Thank you for detailed explanation and steps.
Can you guide more maybe by sharing your auth client if possible?
Also can you share how you generated a deligated signing identity?

Code probably won’t be open sourced for some time so I wouldn’t bank on it, it’s not a priority for us at this stage but as per the above look inside the auth client lib to see how it works out.

Regards

1 Like

1.Each canister of dapp will return different principal id.
2.In the auth backend of II. It uses domain name as salt to calculate the principal id.

Which is. If you are not using stable and correct web url to get authentication from II. The principal id of login_user is not correct.

So i had proposed a scheme for other types of clients to hook up with II https://github.com/dfinity/internet-identity/issues/332, but not getting active replies yet.

1 Like

From @neeboo 's comment what I understood is when I get a principal id from the II using a website, I cannot use it inside the app. Is this the case?

As long as the website url that you load the iframe from is stable, your users will be able to have a consistent principal. Every different URL will get back a different principal, but as long as it stays the same your users will get back the same Principal ID every time

1 Like

I want to generate a key pair on the app (As @stephenandrews mentioned) and pass on to II. To see how it is being created right now, I was cehcking II front-end files. As I think right now, when no key is passed, a key is generated on first visit to II site. I could not find which file is generating that key pair and store it in “ic-identity” local storage. Can you guide me? Also the seed(secretKey) that is used, what is it?

Also I can generate a key pair inside app and pass on to II instead of II generating one, right?

https://erxue-5aaaa-aaaab-qaagq-cai.raw.ic0.app/identity/index.html

https://erxue-5aaaa-aaaab-qaagq-cai.raw.ic0.app/identity/classes/ed25519keyidentity.html#generate

2 Likes

This is where it get’s generated: agent-js/index.ts at 8532edffc5e026cff1cc06080b6b72e1a4e89fcd · dfinity/agent-js · GitHub

The process I did to make something work is as follows:

  • Generated a key using Ed25519KeyIdentity in an app
  • Sent the public key to my website URL which acts as a proxy
  • Display a message to ensure the user wants to continue
  • I made a custom login method (so I made a custom auth-client file) which was named login_external and contained an extra argument “public key”
  • This was pretty similar to the current one, except it created the local key using only and no private key (which does work)
  • Normal II flow
  • Return the DelegatedIdentity back to the app and load it as if it were fetched locally

It’s not easy if you don’t know your way around JS.

2 Likes

Thank you. Any reason you created a custom auth client instead of passing options to AuthClient.create ? I see it has a “key = options.identity;” which seems to be using this option instead of getting the key from browser local storage if used.

ONly reason I can think of is if it only accepts a public/private pair and not just public (I think that is what you are saying in point 5)? Can we just set the private to empty though if that is the reason?

If so I believe the change in that file is the line “key = identity_1.Ed25519KeyIdentity.fromJSON(maybeIdentityStorage);” to eual the key to the public key received from request?

1 Like

You could prob try an empty one. the Ed25519KeyIdentity constructor just asks for public and private key. TBH I skipped the auth.create and called auth.login directly, your method is probably better though if it doesn’t require the custom hack that I did.

1 Like