Web Authentication and Windows Hello
This documentation is archived and is not being maintained.
The Web Authentication API in Microsoft Edge enables web applications to use Windows Hello and external FIDO2 devices for user authentication so that you and your users can avoid all the hassles and risks of password management, including password guessing, phishing, and key-logging attacks. The current Microsoft Edge implementation is based on the Candidate Recommendation of the Web Authentication specification.
Important
This topic will show you how to try out Windows Hello and FIDO2 authentication with Microsoft Edge.
Using Web Authentication, the server sends down a plain text challenge to the browser. Once Microsoft Edge is able to verify the user through Windows Hello or an external FIDO2 device, the system will sign the challenge with a private key previously provisioned for this user and send the signature back to the server. If the server can validate the signature using the public key it has for that user and verify the challenge is correct, it can authenticate the user securely. With asymmetric cryptography such as this, the public key is meaningless on its own and the private key is never shared. Furthermore, the private key can never be moved from secure elements or modern systems with TPM-enabled hardware.
There are two basic steps to using the Web Authentication API:
- Register your user with
create
- Authenticate your user with
get
The following dev guide will walk you through this flow using the WebAuthn Sample App.
Register your user
Acting as an identity provider, you will first need to create a Web Authentication credential for your user with the navigator.credentials.create
method. Before you register that credential to the user on your server, you will need to confirm the identity of the user. This can be done by sending the user an email confirmation or asking them to use their traditional login method.
The create
method takes the following parameters:
relying party information
rp: {
name: "WebAuthn Sample App",
icon: "https://example.com/rpIcon.png"
},
user account information
user: {
id: stringToArrayBuffer("some.user.id"),
name: "[email protected]",
displayName: "Bob Smith",
icon: "https://example.com/userIcon.png"
},
crypto parameters
pubKeyCredParams: [
{
//External authenticators support the ES256 algorithm
type: "public-key",
alg: -7
},
{
//Windows Hello supports the RS256 algorithm
type: "public-key",
alg: -257
}
],
authenticator selection parameters
authenticatorSelection: {
//Select authenticators that support username-less flows
requireResidentKey: true,
//Select authenticators that have a second factor (such as PIN, Bio)
userVerification: "required",
//Selects between bound or detachable authenticators
authenticatorAttachment: "platform"
},
other options
//Select larger timeout values, as Microsoft Edge shows UI
timeout: 50000,
//an opaque challenge that the authenticator signs over
challenge: challenge,
//prevent re-registration by specifying existing credentials here
excludeCredentials: [],
//specifies whether you need an attestation statement
attestation: "none"
You can use credential creation parameters to configure the credential you want to create. In particular, you can choose to create a Windows Hello credential by setting authenticatorAttachment
to platform
, or a roaming credential on an external FIDO2 device by setting authenticatorAttachment
to cross-platform
.
When you use the create
method, Microsoft Edge will first ask the user to verify their presence by scanning their face or fingerprint, entering a PIN, or taking action on an external FIDO2 device. Once this step is completed the authenticator will generate a publicprivate key pair and store the private key. These credentials are created per origin, per account, and cannot be extracted because they are stored securely to the authentication device.
The resulting promise returns an attestation object representing the new credential. The attestation object contains the public key for the credential. You'll send this object to the server for validating future authentications. Before sending back to the server, you'll need to base64-encode the raw data.
Client
<script>
navigator.credentials.create({
publicKey: createCredentialOptions
}).then(rawAttestation => {
var attestation = {
id: base64encode(rawAttestation.rawId),
clientDataJSON: arrayBufferToString(rawAttestation.response.clientDataJSON),
attestationObject: base64encode(rawAttestation.response.attestationObject)
};
return rest_put("/credentials", attestation);
})
</script>
The server should then decode the attestation object, perform verification steps, extract the public key for this credential, and store it for future authentications. A detailed list of steps can be found in the credential registration algorithm in the WebAuthn specification.
Server
attestationObject = cbor.decodeFirstSync(Buffer.from(attestation.attestationObject, 'base64'));
authenticatorData = parseAuthenticatorData(attestationObject.authData);
var credential = await storage.Credentials.create({
id: authenticatorData.attestedCredentialData.credentialId.toString('base64'),
publicKeyJwk: authenticatorData.attestedCredentialData.publicKeyJwk,
signCount: authenticatorData.signCount
});
Authenticate your user
Once the credential is created on the client, the next time the user attempts to log into the site you can offer to sign them in using their Web Authentication credential instead of a password with a call to navigator.credentials.get
.
The get
method takes the challenge as its only required parameter. The challenge is an opaque sequence of bytes that the server will send down to a client to sign with the user's private key. For example:
Server
var jwt = require('jsonwebtoken');
var jwt_secret = "defaultsecret";
fido.getChallenge = () => {
return jwt.sign({}, jwt_secret, {
expiresIn: 120 * 1000
});
};
After retrieving a challenge from the server, you'll call the get API along with credential request options. Microsoft Edge will show a prompt, which will verify the identity of the user using Windows Hello or an external FIDO2 device. After the user is verified, the challenge will be signed within the TPM or FIDO2 device and the promise will return with an assertion object that contains the signature and other metadata for you to send to the server.
Client
var credentialRequestOptions = {
//specifies which credential IDs are allowed to authenticate the user
//if empty, any credential can authenticate the users
allowCredentials: allowCredentials,
//an opaque challenge that the authenticator signs over
challenge: challenge,
//Select larger timeout values, as Microsoft Edge shows UI
timeout: 50000
};
navigator.credentials.get({
publicKey: credentialRequestOptions
}).then(rawAssertion => {
var assertion = {
id: base64encode(rawAssertion.rawId),
clientDataJSON: arrayBufferToString(rawAssertion.response.clientDataJSON),
userHandle: base64encode(rawAssertion.response.userHandle),
signature: base64encode(rawAssertion.response.signature),
authenticatorData: base64encode(rawAssertion.response.authenticatorData)
};
return rest_put("/assertion", assertion);
})
Once you receive the assertion on the server, you will need to validate the signature to authenticate the user. The following is some sample code. A detailed list of steps can be found in the assertion verification algorithm in the WebAuthn specification.
Server
var jwkToPem = require('jwk-to-pem')
var crypto = require('crypto');
...
// Using credential’s id attribute, look up the corresponding
// credential public key.
var credential = await storage.Credentials.findOne({
id: assertion.id
});
//Refer to sample to see how to verify client data and authenticator data
...
//Using the credential public key from lookup, verify that sig is a valid
//signature over the binary concatenation of authData and hash.
var publicKey = credential.publicKeyJwk;
var verify = (publicKey.kty === "RSA") ? crypto.createVerify('RSA-SHA256') : crypto.createVerify('sha256');
verify.update(authData);
verify.update(hash);
if (!verify.verify(jwkToPem(publicKey), sig))
throw new Error("Could not verify signature");
//Verify signCount has increased or is zero
if (authenticatorData.signCount != 0 &&
authenticatorData.signCount < credential.signCount) {
throw new Error("Received signCount of " + authenticatorData.signCount +
" expected signCount > " + credential.signCount);
}
Implementation notes
Supported platforms
- The Candidate Recommendation version of the Web Authentication API can be used from Microsoft Edge beginning with EdgeHTML 18 (Windows Insider Preview version 17713 or newer).
- The prefixed, preview version of the Web Authentication API has been removed and is no longer available.
- The Web Authentication API is not yet available to UWP apps and PWAs.
- Internet Explorer does not support the Web Authentication API.
Supported authenticators
With the Web Authentication API in Microsoft Edge, you can authenticate users with the following technologies:
- Windows Hello Enables passwordless on-device authentication with face, fingerprint, or PIN
- FIDO2 Enables passwordless roaming authentication with a removable device and a fingerprint or PIN
- U2F Enables strong second factor authentication for websites that are not ready to move to a passwordless model
Special considerations for Windows Hello
A few things to note when using the Windows Hello authenticator:
- You can detect if Windows Hello is available on a PC by calling the
isUserVerifyingPlatformAuthenticatorAvailable
API. Learn more about this API here. - When creating a credential for Windows Hello, you should set
authenticatorAttachment
toplatform
for the best user experience. - Windows Hello only supports RS256 (alg -257) as its public key algorithm. Be sure to specify this algorithm when creating a credential.
- To receive a TPM attestation statement, set attestation to "direct" when calling the
create
API. TPM attestation is a best effort. Only PCs with TPM 2.0 will return a TPM attestation statement, and the attestation process could fail for a variety of reasons. - Windows Hello employs a variety of ways to protect user credentials. You can check which method has been used to protect a credential by consuming the AAGUID field in the attestation object returned at credential creation. The following is the list of AAGUIDs that Windows Hello may return:
- Software backed authenticators
- Windows Hello software authenticator:
6028B017-B1D4-4C02-B4B3-AFCDAFC96BB2
- Windows Hello VBS software authenticator:
6E96969E-A5CF-4AAD-9B56-305FE6C82795
- Windows Hello software authenticator:
- Trusted Platform Module (TPM) backed authenticators
- Windows Hello hardware authenticator:
08987058-CADC-4B81-B6E1-30DE50DCBE96
- Windows Hello VBS hardware authenticator:
9DDD1817-AF5A-4672-A2B9-3E3DD95000A9
- Windows Hello hardware authenticator:
- Software backed authenticators
API surface
- Microsoft Edge has a complete implementation of the Candidate Recommendation version of the core Web Authentication specification.
- The AppID extension is supported.
- No other extensions are supported.
Demos
Specification
Web Authentication: An API for accessing Public Key Credentials