RangerRick
RangerRick

Reputation: 296

How to Send PublicKeyCredential to server?

Preface

I am new to cybersecurity. I've always been hesitant to implement an authentication system into personal projects because I was scared by the security implications (mainly passwords and authenticating a user). However, I am very excited about WebAuthn and Apple's Passkeys because this standard promises to be safer and should mean less responsibility for me! However, I have had a nightmare of a time trying to setup what I thought should be a simple demo project. There just isn't enough information or examples to work off of.

Problem

I have created a simple .NET 6 Web API project and a simple Angular project. Here is the flow so far:

  1. User enters a username in Angular App to register with
  2. Angular asks the server for a challenge. The server then uses the Fido2 Nuget Package to generate the challenge
  3. Angular receives the challenge and generates a new PublicKeyCredential using the challenge and calling navigator.credentials.create(...);

The above works perfectly. The next step should be to send the new PublicKeyCredential to the server so the server can store this credential for authentication later. The problem is that this PublicKeyCredential uses ArrayBuffers that cannot be serialized and sent to the server (at least not easily). Am I just doing this wrong? I just simply cannot find any solid and reliable way to get the PublicKeyCredential back to the server.

What I have tried

  1. I have tried encoding the ArrayBuffers to strings and base64 strings as suggested here but this has not worked for me. When the credential gets to the server, I decode the byte[], and attempt to call _fido2.MakeNewCredentialAsync(...) I get a weird error that says the "Attestation Object is invalid. Unhandled State. Was SimpleValue."
  2. I tried the suggestion outlined in this post but this package also assumes that the server will also be using this package. My server is an ASP.NET Web API, not a Node.js application so I didn't know how to use this library.
  3. I have looked at the Demo Library provided by the Fido2 Nuget Package. The problem with this implementation is that the "Front End" and "Back End" are hosted together using a framework I'm not familiar with. Because of this, they can cut a few corners. They don't have to send the PublicKeyCredential 'back' to the server because it is already on the server! I'd like to have my Angular App and Server be separated (If possible)

Conclusion

If anyone has any examples of WebAuthn working in a very simple environment, I would love to take a look. Or if you have suggestions for me on my implementation that is also welcome!

Upvotes: 1

Views: 1470

Answers (2)

RangerRick
RangerRick

Reputation: 296

While the answers to this question did ultimately help me get the PublicKeyCredential to the server (through much weeping and gnashing of teeth), it ultimately proved to be useless because of the problem outlined in this post. WebAuthn doesn't seem to be designed for 'split architecture'. Meaning that you must host your Web Application and your API on the same domain.

Because of this I am basically rethinking my entire approach and starting over trying to implement WebAuthn. Wish me luck!

Even as I type this answer I still have doubts. This just simply can't be the case can it? How are mobile applications supposed to implement WebAuthn if the FIDO2 exchange must happen on the same domain? Are mobile apps expected to load some kind of web view? Are all Web Applications expected to be hosted on the same domain as the Relying party? Or expected to load some sort of iframe? I am very confused, but determined to make WebAuthn work for me.

Upvotes: 1

agl
agl

Reputation: 1662

PublicKeyCredential.response, after a create call, will be an AuthenticatorAttestationResponse. On that object are the functions getPublicKey and getAuthenticatorData (see 5.2.1.1), which will get you the information that you need. But they do, indeed, both return ArrayBuffers.

You can base64-encode an ArrayBuffer, a, with something like btoa(String.fromCharCode.apply(null, new Uint8Array(a))).

Upvotes: 2

Related Questions