Closed varunlohade closed 1 month ago
Please take a look at the example app for how to integrate the authenticator in your app: https://github.com/flutter-institute/webauthn/blob/master/example/lib/main.dart
This is designed to work as the authenticator portion of Webauthn, so it's expecting to receive information from a Relying Party (your back-end app). That can then be passed through the WebApi
helper methods to interact with the authenticator.
Hi!
How can I obtain the public key when creating the credential? I have tried the following code:
var attestationBytes = attestation.asCBOR(); var attestationJson = attestation.asJSON(); However, I only received authData without the key.
@majdslmt For the currently used key type (ES256), the public key bytes are the last 77 bytes of the attestation's authData.
So you can retrieve it by using attestation.authData.sublist(attestation.authData.length - 77)
See https://github.com/flutter-institute/webauthn/blob/master/lib/src/models/attestation.dart#L32 where the structure of authData is documented.
However, as the authenticator you shouldn't be worrying about extracting the public key from the attestation. That's something the Relying Party will do when they validate the response. What's your use case here?
I want to save the public key in the backend, but I can't extract the public key from authData. Also, when using this code, attestation.authData.sublist(attestation.authData.length - 77) didn't work to get the public key as string data. @killermonk
@majdslmt that's because authData
is a Uint8List
, so the sublist is the list of bytes that make up the public key data. If you want to save that data as a string, you'll need to do some encoding on it. Which format are you trying to store it in?
To be much more verbose.
The public key that is stored in the authData
is encoded in COSE_Key format per https://www.w3.org/TR/webauthn-2/#sctn-attested-credential-data and https://datatracker.ietf.org/doc/html/rfc8152#section-7
The byte data you get from the authData
is that encoded format, so you can parse it an re-encode it however you want. I had a script that encoded this into an RSA style format. I'll see if I can find it today.
You can see where it is encoded here: https://github.com/flutter-institute/webauthn/blob/master/lib/src/util/credential_safe.dart#L147 and you'll be able to use the cbor
library to decode it so you don't have to.
I want to get the response as this payload to be able to use @simplewebauthn/server in server side {"id":"ASBmohREs1OhTB6s_EJY-hIwyiQuGbklL-mXK-tmVnmR5N4rlg_TRlrOf-olrhRQlasoGZOabDM4oppcnj0fn0Y","user":"test","rawId":"ASBmohREs1OhTB6s_EJY-hIwyiQuGbklL-mXK-tmVnmR5N4rlg_TRlrOf-olrhRQlasoGZOabDM4oppcnj0fn0Y","response":{"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjFSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQEgZqIURLNToUwerPxCWPoSMMokLhm5JS_plyvrZlZ5keTeK5YP00Zazn_qJa4UUJWrKBmTmmwzOKKaXJ49H59GpQECAyYgASFYIEjOcsLFskQtV98RJaSq5QzeJ6s-JqDUZLCpGP495Ew1Ilgg07dunytQNNIHKKF5q-OwC1lbMC2b5JdBdtwlK9InYx0","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiakg3MjZvV1gtdkFzLWIyUm9XZE9SZlZyQWR1aEZFWDNfbjhUeTdOUlpzZyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMCIsImNyb3NzT3JpZ2luIjpmYWxzZX0","transports":["hybrid","internal"],"publicKeyAlgorithm":-7,"publicKey":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESM5ywsWyRC1X3xElpKrlDN4nqz4moNRksKkY_j3kTDXTt26fK1A00gcooXmr47ALWVswLZvkl0F23CUr0idjHQ","authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQEgZqIURLNToUwerPxCWPoSMMokLhm5JS_plyvrZlZ5keTeK5YP00Zazn_qJa4UUJWrKBmTmmwzOKKaXJ49H59GpQECAyYgASFYIEjOcsLFskQtV98RJaSq5QzeJ6s-JqDUZLCpGP495Ew1Ilgg07dunytQNNIHKKF5q-OwC1lbMC2b5JdBdtwlK9InYx0"},"type":"public-key","clientExtensionResults":{"credProps":{"rk":false}},"authenticatorAttachment":"cross-platform"} @killermonk
You'll want to check out WebAPI.createAttestationResponse
here https://github.com/flutter-institute/webauthn/blob/master/lib/src/web_api.dart#L132
That will return you most of what you are looking for. The server should theoretically be able to handle this response. The WebAPI
stuff are helpers I quickly threw in to test against one use case, though, so they might be incomplete.
I was looking over https://www.w3.org/TR/webauthn-2/#authenticatorattestationresponse and the response object the WebAPI helper creates has all the "attributes" available, but does not have any of the "operations" implemented.
Also, I haven't built in support for extensions, yet.
@killermonk thanks! now I am trying the WebApi but still getting this error ""type 'Null' is not a subtype of type 'Map<dynamic, dynamic>' in type cast" " when create the CreateCredentialOptions with fake payload to test this { "authenticatorExtensions": "", "clientDataHash": "LTCT/hWLtJenIgi0oUhkJz7dE8ng+pej+i6YI1QQu60=", "credTypesAndPubKeyAlgs": [ ["public-key", -7] ], "excludeCredentials": [{ "type": "public-key", "id": "lVGyXHwz6vdYignKyctbkIkJto/ADbYbHhE7+ss/87o=" }], "pubKeyCredParams": [ { "alg": -8, "type": "public-key" }, { "alg": -7, "type": "public-key" }, { "alg": -257, "type": "public-key" } ], "requireResidentKey": true, "requireUserPresence": true, "requireUserVerification": false, "rp": { "name": "webauthn.io", "id": "webauthn.io" }, "user": { "name": "testuser", "displayName": "Test User", "id": "/QIAAAAAAAAAAA==" } } Do you have an example of optionsPayload to Create a New Credential and Make an Assertion
@killermonk I think the problem is in fromjson function but my solution is build the payload not from json
// Convert 'rp', 'user', and 'authenticatorSelection' directly from jsonMap. final rp = RpEntity.fromJson(jsonMap['rp']); final user = UserEntity.fromJson(jsonMap['user']); final authenticatorSelection = AuthenticatorSelectionCriteria.fromJson(jsonMap['authenticatorSelection']);
// Initialize the list with a capacity for better performance since its length is known.
var keys = List
// Construct the PublicKeyCredentialCreationOptions object. final p = PublicKeyCredentialCreationOptions( rpEntity: rp, userEntity: user, challenge: utf8.encode(jsonMap['challenge']), authenticatorSelection: authenticatorSelection, pubKeyCredParams: keys, );
// Finally, create the credential options object. final rpOptions = CreateCredentialOptions(publicKey: p);
@majdslmt sorry for my delay here, I've been swamped with work so I haven't had time to look into this yet. Thanks for the details, though. I'm hoping to be able to dig in over the next few days.
@majdslmt I need to apologize for my delay here. My personal PC's SSD died and by the time I'd gotten things all fixed up I forgot I had this pending issue that we were discussing.
I went through your payload, and you're getting the current error because it is malformed. If you take a look at the CreateCredentialOptions model at lib/src/models/create_credential_options.dart you can see the properties that are required and how the object should be structured.
First, the only key that should exist on the top level is "publicKey", and all the other options need to be moved inside that as a nested object. That's where the Null error is coming from: it can't find that key. Not the greatest error message of all time from the generated code.
Next, your options need to be restructured slightly.
None of these options are supported in this manner.
"requireResidentKey": true,
"requireUserPresence": true,
"requireUserVerification": false,
They need to be moved into the "authenticatorSelection" object as follows:
"authenticatorSelection": {
"requireResidentKey": true,
"userVerification": "required"
}
Also, you are missing the "challenge" data. With those modifications you should be able to use the fromJson options now. End result is options that look like this:
{
"publicKey": {
"rp": {
"name": "webauthn.io",
"id": "webauthn.io"
},
"user": {
"name": "testuser",
"displayName": "Test User",
"id": "/QIAAAAAAAAAAA=="
},
"clientDataHash": "LTCT/hWLtJenIgi0oUhkJz7dE8ng+pej+i6YI1QQu60=",
"credTypesAndPubKeyAlgs": [
["public-key", -7]
],
"excludeCredentials": [{
"type": "public-key",
"id": "lVGyXHwz6vdYignKyctbkIkJto/ADbYbHhE7+ss/87o="
}],
"pubKeyCredParams": [
{ "alg": -8, "type": "public-key" },
{ "alg": -7, "type": "public-key" },
{ "alg": -257, "type": "public-key" }
],
"challenge": "AQIDBA==",
"authenticatorSelection": {
"requireResidentKey": true,
"userVerification": "required"
}
}
}
I tried using this package, but it just shows the biometric(face id or fingerprint), I want to implement passkey in my application, Any way I can do it with webauthn package