Credentials
Credentials is a virtual WebAuthn authenticator scoped to a BrowserContext. It lets tests register passkeys and answer navigator.credentials.create() / navigator.credentials.get() ceremonies in the page, without a real authenticator or hardware security key.
There are two common ways to use it:
Usage: seed a known credential
- Sync
- Async
context = browser.new_context()
# A passkey your backend already provisioned for a test user.
context.credentials.create(
"example.com",
id=known_credential_id, # base64url
user_handle=known_user_handle, # base64url
private_key=known_private_key, # base64url PKCS#8 (DER)
public_key=known_public_key, # base64url SPKI (DER)
)
context.credentials.install()
page = context.new_page()
page.goto("https://example.com/login")
# The page's navigator.credentials.get() is answered with the seeded passkey.
context = await browser.new_context()
# A passkey your backend already provisioned for a test user.
await context.credentials.create(
"example.com",
id=known_credential_id, # base64url
user_handle=known_user_handle, # base64url
private_key=known_private_key, # base64url PKCS#8 (DER)
public_key=known_public_key, # base64url SPKI (DER)
)
await context.credentials.install()
page = await context.new_page()
await page.goto("https://example.com/login")
# The page's navigator.credentials.get() is answered with the seeded passkey.
Usage: capture a passkey, then reuse it
- Sync
- Async
# setup test: let the app register a passkey, then save it.
context = browser.new_context()
context.credentials.install()
page = context.new_page()
page.goto("https://example.com/register")
page.get_by_role("button", name="Create a passkey").click()
# Read back the passkey the page registered — it includes the private key.
[credential] = context.credentials.get(rp_id="example.com")
with open("playwright/.auth/passkey.json", "w") as f:
json.dump(credential, f)
# setup test: let the app register a passkey, then save it.
context = await browser.new_context()
await context.credentials.install()
page = await context.new_page()
await page.goto("https://example.com/register")
await page.get_by_role("button", name="Create a passkey").click()
# Read back the passkey the page registered — it includes the private key.
[credential] = await context.credentials.get(rp_id="example.com")
with open("playwright/.auth/passkey.json", "w") as f:
json.dump(credential, f)
- Sync
- Async
# later test: seed the captured passkey so the app starts already enrolled.
with open("playwright/.auth/passkey.json") as f:
credential = json.load(f)
context = browser.new_context()
context.credentials.create(
credential["rpId"],
id=credential["id"],
user_handle=credential["userHandle"],
private_key=credential["privateKey"],
public_key=credential["publicKey"],
)
context.credentials.install()
page = context.new_page()
page.goto("https://example.com/login")
# navigator.credentials.get() resolves the captured passkey — already signed in.
# later test: seed the captured passkey so the app starts already enrolled.
with open("playwright/.auth/passkey.json") as f:
credential = json.load(f)
context = await browser.new_context()
await context.credentials.create(
credential["rpId"],
id=credential["id"],
user_handle=credential["userHandle"],
private_key=credential["privateKey"],
public_key=credential["publicKey"],
)
await context.credentials.install()
page = await context.new_page()
await page.goto("https://example.com/login")
# navigator.credentials.get() resolves the captured passkey — already signed in.
Defaults
Methods
create
Added in: v1.61Seeds a virtual WebAuthn credential and returns it.
With only rp_id, generates a fresh ECDSA P-256 keypair, credential id and user handle. The seeded credential is discoverable (resident), so the page can resolve it from both username-then-passkey and usernameless passkey flows. The returned object carries the private and public keys, so it can be persisted to disk and re-seeded in a later test.
To import a known credential, supply all four of id, user_handle, private_key and public_key together.
Call credentials.install() before navigating to a page that uses WebAuthn.
Usage
credentials.create(rp_id)
credentials.create(rp_id, **kwargs)
Arguments
-
Relying party id (typically the site's effective domain).
-
Base64url-encoded credential id. Auto-generated if omitted.
-
Base64url-encoded PKCS#8 (DER) private key. Auto-generated if omitted.
-
Base64url-encoded SPKI (DER) public key. Auto-generated if omitted.
-
Base64url-encoded user handle. Auto-generated if omitted.
Returns
delete
Added in: v1.61Removes a credential from the authenticator by its id. Works for any credential currently held — both those seeded with credentials.create() and those the page registered itself by calling navigator.credentials.create().
Usage
credentials.delete(id)
Arguments
Returns
get
Added in: v1.61Returns every credential currently held by the authenticator, optionally filtered by rp_id or id. This includes both credentials seeded with credentials.create() and credentials the page registered itself by calling navigator.credentials.create().
Each returned credential includes its private and public keys, so a passkey the app just registered can be saved and re-seeded into a later test with credentials.create() — see the second example in the class overview.
Usage
credentials.get()
credentials.get(**kwargs)
Arguments
-
Only return the credential with this base64url-encoded id.
-
Only return credentials for this relying party id.
Returns
install
Added in: v1.61Installs the virtual WebAuthn authenticator into the context, overriding navigator.credentials.create() and navigator.credentials.get() in all current and future pages. Call this before the page first touches navigator.credentials.
Required: until credentials.install() is called, no interception is in place and the page sees the platform's native (or absent) WebAuthn behaviour. Seeding credentials with credentials.create() without installing populates the authenticator, but the page will never see those credentials.
Usage
credentials.install()
Returns