Open SphiwokuhleS opened 3 years ago
There's no Webauthn support yet in Playwright. But Please upvote if you'd like to see one!
Just want to add a note, that I've implemented virtualAuthenticator (based ofcourse on WebAuthn) in Python+Selenium.
Trying to do the same on PlayWright (in TypeScript) - the obstacle is that it should have "Webdriver" support, as it seems (according to official documentation of WebAuthn) that it needs it.
The implementation is done via REST api commands to the driver.
please let me know if there any progress
Any progress by any chance? :)
While it would certainly be nicer to have Playwright APIs that provide normalized WebAuthn virtual authenticator functionality across all three browsers, it's possible to interact with WebAuthn virtual authenticators in Chromium-only tests using the Chromium Dev Tools protocol's WebAuthn messages and Playwright's CDPSession.
For example, to create a FIDO2/CTAP2 virtual authenticator that automatically simulates user presence and verification, do something like this:
const cdpSession = await page.context().newCDPSession(page);
await cdpSession.send('WebAuthn.enable');
await cdpSession.send('WebAuthn.addVirtualAuthenticator', {
options: {
protocol: 'ctap2',
ctap2Version: 'ctap2_1',
hasUserVerification: true,
transport: 'usb',
automaticPresenceSimulation: true,
isUserVerified: true,
}
});
// Interact with your site to trigger navigator.credentials.create(), and the virtual authenticator will automatically answer all the necessary prompts for registration.
If Playwright provided a way to use the WebDriver protocol directly with Firefox or Safari, similar to CDPSession, it might be possible to create workarounds for those browsers too without first party Playwright support. But that doesn't seem to be possible.
Any progress on this? Can anyone help with the update on this? Please help understand the status of WebAuthn support as we want to automate authentication flows @aslushnikov
@sumitdnaik there's been no progress regarding WebAuthn automation in Playwright as of May 30, 2023
Thank you for the reply! We had chosen Playwright to automate our login flows and WebAuthn is an important part of 2FA flows we have. Is there any alternate way/workaround to automate this using Playwright? If anyone can help, it would be great. @SphiwokuhleS @dbalikhin Would like to understand what approach you took.
Hi barrysimpson, I was unable to get it to work. I used your code snippet and I saw that the "Enable virtual authenticator environment" is still disabled in the browser that opened. Any thoughts maybe ? I am using latest chrome and Playwright
Hi, any progress, update or workaround regarding WebAuthn automation in Playwright @aslushnikov @yury-s ? Thank you
I was unable to get it to work. I used your code snippet and I saw that the "Enable virtual authenticator environment" is still disabled in the browser that opened. Any thoughts maybe ? I am using latest chrome and Playwright
Same for me. I can do it manually by going into chrome dev tools and turning it on in the UI, but that code snippet doesn't seem to do anything.
To get to the manual settings, go to the three dot menu and choose WebAuth, then click enable:
@banshee hard to say what could be going on without seeing an example test. It continues to work for me on the latest playwright version.
Something that might be worth noting is that I create a new CDPSession
, enable WebAuthn, and add a new virutal authenticator inside every single test()
block. I do not do this in beforeEach()
or beforeAll()
, which would certainly be tempting. I don't recall exactly why. But BrowserContext.newCDPSession()
requires a Page
or Frame
parameter, which implies that the CDPSession
is tied to a particular Page
instance, and that implies subsequent new Page
instances may not automatically inherit the CDPSession
and the WebAuthn API's enabled state of a previous Page
instance. Since each test()
creates a new Page
instance for you, you probably have to do the virtual authenticator setup work inside every test.
@barrysimpson your advice was spot on. I was calling your code snippet before visiting the page. It works now.
Future readers should note that the UI does not show authenticators added this way as far as I can see.
Please consider adding webauthn support also, as this is becoming more and more mainstream and because some of our apps only use webauthn, there is no workaround for them and thus preventing us from moving to Playwright
Would be really nice to have this added to Playwright.
example.spec.js
const { chromium } = require("playwright");
const { test, expect } = require("@playwright/test");
const {
enableWebAuthn,
addVirtualAuthenticator,
removeVirtualAuthenticator,
addCredential,
getCredentials,
} = require("../src/webauthn");
test("test passkeys example.com", async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
// Create a new CDP session
const client = await context.newCDPSession(page);
await enableWebAuthn(client);
const authenticatorId = await addVirtualAuthenticator(client);
await addCredential(client, authenticatorId);
await getCredentials(client, authenticatorId);
await removeVirtualAuthenticator(client, authenticatorId);
});
webauth.js
const CREDENTIAL_ID = "";
const enableWebAuthn = (client) => {
return client.send("WebAuthn.enable");
};
const addVirtualAuthenticator = (client) => {
return client
.send("WebAuthn.addVirtualAuthenticator", {
// config authenticator
options: {
protocol: "ctap2",
transport: "usb",
hasResidentKey: true,
hasUserVerification: true,
isUserVerified: true,
},
})
.then((result) => {
console.log("WebAuthn.addVirtualAuthenticator", result);
return result.authenticatorId;
});
};
const removeVirtualAuthenticator = (client, authenticatorId) => {
client
.send("WebAuthn.removeVirtualAuthenticator", {
authenticatorId,
})
.then((result) => {
console.log("WebAuthn.removeVirtualAuthenticator", result);
});
};
const addCredential = (client, authenticatorId) => {
client
.send("WebAuthn.addCredential", {
authenticatorId,
credential: {
credentialId: CREDENTIAL_ID,
isResidentCredential: true,
rpId: "example.com",
privateKey: ``,
userHandle: "",
signCount: Math.round(
(new Date().getTime() - 1704444610871) / 1000 / 2
),
// signCount: 2,
},
})
.then((result) => {
console.log("WebAuthn.addCredential", result);
});
};
const removeCredential = (client, { authenticatorId, credentialId }) => {
client
.send("WebAuthn.removeCredential", {
authenticatorId,
credentialId,
})
.then((result) => {
console.log("WebAuthn.removeCredential", result);
});
};
const getCredentials = (client, authenticatorId) => {
client
.send("WebAuthn.getCredentials", {
authenticatorId,
})
.then((result) => {
console.log("WebAuthn.getCredentials", result);
});
};
module.exports = {
enableWebAuthn,
addVirtualAuthenticator,
removeVirtualAuthenticator,
addCredential,
removeCredential,
getCredentials,
};
Hope this help. I use CDP to create passkeys. https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/
Is there a way to test FIDO2 CTAP2 Webauthn?