---
url: 'https://www.corbado.com/blog/fido2-security-key-vs-passkey'
title: 'FIDO2 Security Key vs Passkey: U2F, PIN and AAL3'
description: 'Second factor or passkey on the key? How fido-u2f and packed differ, why a PIN appears unasked and what "FIDO Certified" means for AAL3.'
lang: 'en'
author: 'Vincent Delitz'
date: '2026-10-31T22:29:12.949Z'
lastModified: '2026-11-01T09:33:29.021Z'
keywords: 'fido2 security key vs passkey, fido u2f security key, security key second factor, passkey on security key, aal3 security key, webauthn attestation fido-u2f packed, security key pin prompt'
category: 'WebAuthn Know-How'
---

# FIDO2 Security Key vs Passkey: U2F, PIN and AAL3

## Key Facts

- **A security key can be used in two ways.** As a second factor after the password
  (U2F-style, touch only) or as a passkey that replaces the password (key plus PIN). Both
  can reach NIST AAL3.
- **AAL3 needs proof that the key is real hardware.** The server only gets that proof from
  attestation. Without it, a password manager can register a synced passkey in place of
  the key.
- **The same request returns two attestation formats.** In our data Chrome on macOS
  returned `fido-u2f` for 21 of 26 U2F-style registrations, Safari on macOS returned
  `packed` for 9 of 11. A server has to check both.
- **"Discouraged" does not mean "no PIN".** Whether a PIN appears depends on the key, the
  browser and the operating system. On macOS, U2F-style logins went through without a PIN
  in every test session; on Windows the operating system, not the browser, decides.
- **"FIDO Certified" is a Metadata Service check.** 81% of 448 attested security key
  registrations in the Passkeys Debugger would pass "certified, L1 or higher".

_State of the data: Passkeys Debugger registrations and logins through 1 November 2026,
checked against FIDO Metadata Service BLOB 288. Samples per browser are small, so read the
browser numbers as direction, not as market share. We will update the numbers as more
registrations come in._

## 1. Introduction

Banks, governments and enterprises that roll out security keys weigh how to implement and
use them. Three decisions shape that work, and most guides blur them together: how the key
is used, how the server identifies it and what the user sees when they touch it.

This article separates them. It compares the security key as a second factor with the
passkey on a security key, explains the two attestation formats `fido-u2f` and `packed`,
shows why a PIN prompt appears although the site asked for none and defines what "only
FIDO Certified keys" means in practice. Every claim comes with real registration examples from the
[Passkeys Debugger](https://www.passkeys-debugger.io), so you can reproduce it with your own
key.

If you are choosing hardware, start with our
[best FIDO2 hardware security keys](https://www.corbado.com/blog/best-fido2-hardware-security-keys) guide. If you
want the short answer on terms, our FAQ on the
[difference between a YubiKey and a passkey](https://www.corbado.com/faq/what-is-difference-between-yubikey-passkey)
covers it. This article is for the people who have to implement it.

## 2. Two ways to use a security key

A FIDO2 [security key](https://www.corbado.com/glossary/security-key) does not decide how it is used. The
[relying party](https://www.corbado.com/glossary/relying-party) decides that through the options it sends to
`navigator.credentials.create()`.

![Comparison of a security key as second factor and a passkey on a security key: login steps, WebAuthn options, storage, NIST factors, attestation format, PIN behaviour and lost PIN](https://www.corbado.com/website-assets/second_factor_vs_passkey_on_key_card_0984d8f1ac.png "rounded")

### 2.1 Security key as second factor (U2F-style)

The user enters username and password, then touches the key. The server asks for a
non-discoverable credential (`residentKey: "discouraged"`) and no
[user verification](https://www.corbado.com/blog/webauthn-user-verification) (`userVerification: "discouraged"`).
The key stores nothing: its private key is wrapped into the credential ID that the server
keeps, so the number of accounts per key is unlimited.

This is how FIDO U2F has worked since 2014.

You can try exactly this setup in the debugger with the
[U2F-style security key preset](https://www.passkeys-debugger.io/?preset=create-u2f-style-security-key-only).
The [security key as second factor guide](https://www.passkeys-debugger.io/how-to/security-key-second-factor) walks through the test step by step.

### 2.2 Passkey on a security key

The user touches the key and enters its PIN, no password. The server asks for a
[discoverable credential](https://www.corbado.com/blog/webauthn-resident-key-discoverable-credentials-passkeys)
(`residentKey: "required"`) and user verification (`userVerification: "required"`). The key
stores one credential slot per account, and the PIN or fingerprint on the key is the second
factor.

If the key has no PIN yet, the browser does not fail. It asks the user to set one first and
only then creates the passkey. Every platform does this in its own words:

![When a passkey registration with user verification required meets a security key without a PIN, the browser asks to set one first: Chrome on desktop shows PIN required, set up a new PIN; Safari on macOS and iOS show Set Up Security Key, enter the new PIN; Chrome on Android shows Set a PIN for your security key](https://www.corbado.com/website-assets/security_key_pin_setup_dialogs_card_2c89900772.png "rounded")

That first PIN belongs to the key, not to your service. The user chooses it, the key stores
it and nobody can reset it except by resetting the key, which deletes every passkey on it.

The matching debugger setup is the
[security key passkey preset](https://www.passkeys-debugger.io/?preset=create-security-key-only).

### 2.3 Both can reach AAL3

[NIST SP 800-63B-4](https://www.corbado.com/glossary/authentication-assurance-level) defines AAL3 as authentication
with a phishing-resistant authenticator, a non-exportable key and two factors, with explicit
authentication intent. Both setups fit:

- **Second factor:** a password plus a single-factor cryptographic device. NIST allows this
  combination of a physical authenticator with a password.
- **Passkey on the key:** a multi-factor cryptographic authenticator. The PIN is an
  activation secret that never leaves the key.
- **Intent:** in both cases the key requires a touch for every operation.

AAL3 applies to the whole authentication process, not only the key: NIST also requires FIPS
140 validation, replay resistance and reauthentication limits. This article covers the
authenticator side.

[Synced passkeys](https://www.corbado.com/blog/device-bound-synced-passkeys) do not reach AAL3, because their keys
are exportable by design. That is the catch: the server has to know that it got a key and
not a synced passkey. NIST says verifiers in federal enterprise systems should use
attestation for that, everyone else may. In practice it is the only reliable signal.

### 2.4 Stay with discouraged or required

Both setups above use clear values: `"discouraged"` for the second factor and `"required"`
for the passkey. Large relying parties that want maximum compatibility, Google among them,
deliberately use `"preferred"` instead. It avoids hard failures when a fingerprint sensor or
PIN is not available, and for security keys there are three more reasons:

- **Old U2F-only keys** have no PIN at all. With `"required"` they would be locked out
  completely. With `"preferred"` they still work as a second factor.
- **Keys without a PIN set:** `"required"` forces PIN creation during registration. That is
  friction, and it creates a PIN the user may later forget and nobody can reset.
- **One flow for everything:** Google supported security keys for 2-Step Verification
  since U2F launched in 2014, long before it introduced passkeys in 2023. With
  `"preferred"` the same registration flow and UI serve both: Google accepts every key and
  decides afterwards by the UV flag. With UV the key becomes a full passkey, without it the
  key stays a second factor that only works together with a password.

The price is that the browser, not the server, decides what gets created. We registered a
Yubico Security Key NFC (firmware 5.8) with each combination in the
[Passkeys Debugger](https://www.passkeys-debugger.io) and repeated the Chrome tests with an
older YubiKey 5 NFC that has a PIN set. Both keys gave the same credProtect levels:

| `residentKey` | `userVerification` | Chrome | Safari |
|---|---|---|---|
| `discouraged` | `discouraged` | No credProtect, no PIN | No credProtect, no PIN |
| `preferred` | `discouraged` | credProtect level 2, PIN asked | - |
| `preferred` | `preferred` | credProtect level 2 | Key without PIN: no PIN, user not verified, discoverability unknown |
| `required` | `discouraged` | credProtect level 2, PIN asked | - |
| `required` | `preferred` | **credProtect level 3**, PIN asked | - |
| `required` | `required` | credProtect level 2, PIN asked | - |

Two things decide the outcome:

- **credProps:** a WebAuthn extension in which the browser reports whether it created a
  discoverable credential (`rk: true` or `false`). With `residentKey: "preferred"` it is the
  only way to know. Safari does not return it, so in Safari the server cannot tell what it
  got.
- **credProtect:** Chrome protects every discoverable credential with level 2, so the key
  only answers without a PIN when the server sends the credential ID. One combination,
  `required` with `preferred`, gets level 3: the key then demands its PIN at every login,
  and Safari can fail to complete such logins. Our
  [credProtect article](https://www.corbado.com/blog/webauthn-credprotect-security-keys) covers the details.

With `"discouraged"` or `"required"` none of this is ambiguous. If you choose
`"preferred"`, check the user verified flag after every registration and classify the key,
the way Google does.

> **Side note: a passkey as the second factor.** Some services keep the password and accept a
> passkey as the second factor, on a security key or synced. The
> [AWS console](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_fido.html)
> is the best-known example: IAM users sign in with their password and then confirm with a
> security key or a passkey. Teams usually choose this when a strong second factor is already
> in place and rebuilding the login around passkeys isn't worth it yet. It adds phishing
> resistance without changing the architecture. The assurance level depends on what the
> passkey is: a password plus a synced passkey reaches AAL2, a password plus a security key
> reaches AAL3. A passkey on a security key would be AAL3 even without the password, so
> dropping the password for those keys is the natural next step, but then the server has to
> run two login flows side by side, which is where implementation gets complicated.

## 3. How the server knows which key it got

At registration the key can send an attestation: a statement signed by the manufacturer
that says which model created the credential. The server only receives it when it asks for
it with `attestation: "direct"`. Chrome then shows the user a prompt to share the key's make
and model.

![Flow diagram: a registration with attestation direct returns packed or fido-u2f. Packed is identified by its AAGUID, fido-u2f by the SHA-1 key ID of its certificate. Both are looked up in the FIDO Metadata Service, the chain is checked against the listed root and the key is accepted only if its status is FIDO certified L1 or higher and not revoked](https://www.corbado.com/website-assets/how_a_server_identifies_a_security_key_card_632ad281c8.png "rounded")

### 3.1 Two formats, two generations

| | `fido-u2f` | `packed` |
|---|---|---|
| Origin | FIDO U2F (2014), built only as a second factor | FIDO2: CTAP2 and WebAuthn (2018/19) |
| What the key signs | A fixed U2F message: app hash, challenge hash, key handle, public key | The full authenticator data plus the challenge hash |
| Model identifier | None, the AAGUID is all zeros | The AAGUID |
| Algorithms | ECDSA P-256 only | Several, e.g. ES256 and EdDSA |
| Flags and extensions | Not signed by the key | Signed: user present, user verified, backup eligible, extensions |

U2F was deliberately narrow: one message format, one algorithm, nothing else. FIDO2 added
passwordless login, PINs, discoverable credentials and extensions, all of which live in the
authenticator data that the old U2F signature does not cover. So FIDO2 needed a new format.
WebAuthn kept `fido-u2f` for backwards compatibility: when a browser talks to a key over the
old protocol (CTAP1), it wraps the U2F answer as `fido-u2f`.

### 3.2 Same request, different format

The format is not your choice. It depends on the key and on which protocol the browser
uses. Here are two real U2F-style registration examples from the same day, both from Yubico keys:

![Two real U2F-style registration examples: Chrome on macOS returned fido-u2f with an all-zero AAGUID, identified by certificate key ID as YubiKey 5 Series with NFC, FIDO certified L1. Safari on macOS returned packed with AAGUID 0f083f18, Security Key Series with NFC, FIDO certified L2](https://www.corbado.com/website-assets/fido_u2f_vs_packed_registration_examples_card_4064cbec60.png "rounded")

In the debugger's Decoded panel the difference is visible at a glance. The `fido-u2f`
registration has an AAGUID of all zeros and is named by its attestation certificate key ID:

![Passkeys Debugger Decoded panel for a fido-u2f registration: YubiKey 5 Series with NFC identified by attestation certificate key ID, AAGUID not provided, user verified false, backup eligible false](https://www.corbado.com/website-assets/debugger_decoded_fido_u2f_9691945b59.png "rounded")

The `packed` registration carries its AAGUID directly:

![Passkeys Debugger Decoded panel for a packed registration: Security Key Series with NFC identified by AAGUID 0f083f18, user verified false, backup eligible false](https://www.corbado.com/website-assets/debugger_decoded_packed_a5e1259f09.png "rounded")

Across all attested security key registrations in the debugger the split depends on the
browser:

![Attestation format for U2F-style requests by browser: Chrome on macOS 21 fido-u2f and 5 packed, Safari on macOS 2 fido-u2f and 9 packed, Firefox on Windows 7 packed, Firefox on macOS 3 packed, Chrome on Linux 3 packed. Overall 23 fido-u2f and 31 packed for U2F-style, 362 of 368 packed for passkey-style requests](https://www.corbado.com/website-assets/attestation_format_by_browser_v4_42f93a8b3b.png "rounded")

For passkey-style requests `packed` is almost universal. For U2F-style requests 23 of 54
registrations arrived as `fido-u2f`. A server that only handles `packed` would reject
genuine keys.

### 3.3 Where the certificate key ID comes from

A `fido-u2f` key has no AAGUID, so the FIDO Metadata Service
lists it by the key ID of its attestation certificate. The key ID is not read from the
certificate, it is computed:

1. Take the attestation certificate from `attStmt.x5c[0]`.
2. Take the bare public key from `SubjectPublicKeyInfo.subjectPublicKey`.
3. Hash it with SHA-1. In the registration above that gives
   `b95206228ead492b9e14504abefcb20546b0e53b`.
4. Look the value up in the `attestationCertificateKeyIdentifiers` of the Metadata Service
   entries. Here it matches "YubiKey 5 Series with NFC", certified L1 since May 2020.

The certificate subject reads "Yubico U2F EE Serial 1155109599". That serial identifies a
batch certificate shared by many thousands of keys of the same model, not the individual
key, so attestation does not make a user trackable.

### 3.4 Password managers can take the key's place

Password manager extensions replace `navigator.credentials.create()` in the browser and
offer to save a passkey in their own vault. For a security key rollout that is the wrong
result: the server receives a synced passkey, not a hardware key, and the AAL3 argument from
section 2.3 no longer holds. Three layers protect against it, and only the first one is a
real control:

- **Attestation and FIDO Metadata Service:** password managers usually send attestation
  `"none"` and are not listed as certified hardware. The check from section 5 rejects them,
  whatever the extension does. This is the only layer that proves "hardware only".
- **Backup eligible flag:** a synced passkey is marked BE=1, a credential that lives only on
  a hardware key BE=0. Rejecting BE=1 filters out most password manager passkeys.
- **Hint `"security-key"`:** tells the browser and extensions which authenticator you
  expect. In our test with the 1Password browser extension, the hint was enough: 1Password
  did not intercept the registration and the browser went straight to the key. A hint is a
  request, not a rule, so treat it as a better user experience, not as protection.

## 4. PIN surprise: why a PIN appears although you said "discouraged"

`userVerification: "discouraged"` is a request, not a guarantee. Whether the user is asked
for the key's PIN depends on the key, the browser and the operating system. The numbers below
count test sessions with credentials registered U2F-style, so each person and key counts
once:

![Test sessions with U2F-style credentials in which the key asked for a PIN although userVerification was discouraged. Registration: Chrome on macOS 1 of 21, Chrome on Linux 2 of 5, Firefox on Windows 1 of 3, Safari on macOS 0 of 7, Firefox on macOS 0 of 4. Login: Chrome on macOS 0 of 7, Safari on macOS 0 of 4, Firefox on macOS 0 of 2, Chrome on Linux 1 of 1, Firefox on Windows 0 of 1](https://www.corbado.com/website-assets/pin_prompt_despite_discouraged_v4_e1fe9c0543.png "rounded")

### 4.1 Registration

Three things decide the registration:

- **CTAP 2.0 keys with a PIN set** want the PIN for every CTAP2 registration, even a
  non-discoverable one. Chrome avoids that prompt by talking to the key over the old U2F
  protocol, which is one reason Chrome returns `fido-u2f` so often. In our test an older
  YubiKey 5 NFC with a PIN set returned `fido-u2f` in Chrome without a PIN prompt.
- **CTAP 2.1 keys** support the `makeCredUvNotRqd` option and create a non-discoverable
  credential over CTAP2 without a PIN. Chrome then gets `packed` and no prompt. YubiKeys
  with firmware 5.7 and later belong here.
- **Windows** owns the security key. Since Windows 10 version 1903, Chrome, Edge and Firefox
  do not talk to the key themselves: they hand the request to Windows' own WebAuthn API,
  which shows the "Windows Security" dialog. Chrome's U2F trick is not available there, so
  a CTAP 2.0 key with a PIN set will typically ask for it. The browser makes no difference
  on Windows. On macOS and Linux it is the other way round: each browser talks to the key
  itself over USB or NFC and applies its own rules, which is why Chrome and Safari behave
  differently on the same Mac. Our Windows sample is still small: one of three Firefox
  sessions saw a PIN.

In WebKit's open-source code, the engine behind Safari, there is no fallback to U2F after an
error at registration, only at login. Safari falls back to U2F at registration only when a key
does not answer as a CTAP2 device when Safari first detects it. That is rare, which matches
the mostly `packed` results above: the two `fido-u2f` registrations came from keys that
returned `packed` in other Safari registrations, one of them minutes earlier.

### 4.2 Login

At login, U2F-style credentials went through without a PIN in all seven Chrome sessions
and all four Safari sessions on macOS. Safari falls back to U2F at login when CTAP2 finds no
matching credential, so keys registered over U2F in another browser keep working.

Be careful with one trap when you read your own data. A discoverable credential registered
in Chrome carries credProtect level 2 or 3 on the key (section 2.4). With level 3, or with
level 2 and no credential ID in the request, the key itself demands the PIN at login,
whatever the site asks for. Such logins look like a PIN prompt despite "discouraged", but
they are a property of the credential, not of the browser. Most Windows logins in our data were of that kind; the one
clean Windows login so far, in Firefox, went through without a PIN.

For a bank this matters more than any other detail. A customer who never set a PIN on the
key, or forgot it, gets stuck at a prompt the bank cannot reset. Two consequences follow:

- **Buy keys with CTAP 2.1** for the keys you issue yourself.
- **Test the matrix** of Windows, macOS, Linux, iOS and Android with Chrome, Safari, Edge and
  Firefox before launch, at registration and at login, with one key that has a PIN and one
  that does not.

You can reproduce each case with your own key in the
[U2F-style preset](https://www.passkeys-debugger.io/?preset=create-u2f-style-security-key-only):
the response strip shows whether the user verified flag was set and which format came back.
When a key verified the user although you asked for `"discouraged"`, the debugger explains
why under User verified, for example a discoverable credential or Windows. The
[second factor guide](https://www.passkeys-debugger.io/how-to/security-key-second-factor) shows the typical cases with screenshots.

## 5. What "only FIDO Certified keys" means

"We accept FIDO Certified keys" sounds like a product label. Technically it is a lookup in
the FIDO Metadata Service, and a key passes only when four things hold:

1. Its model is listed, by AAGUID for `packed` or by certificate key ID for `fido-u2f`.
2. Its attestation chain reaches the root certificate listed for that model.
3. Its status reports contain a certification: `FIDO_CERTIFIED`, `_L1`, `_L1plus`, `_L2`,
   `_L2plus`, `_L3` or `_L3plus`.
4. Its latest relevant status is not a block such as `REVOKED`,
   `ATTESTATION_KEY_COMPROMISE` or `USER_KEY_REMOTE_COMPROMISE`.

Being listed is not the same as being certified. The Metadata Service also lists models with
`NOT_FIDO_CERTIFIED` or only a self-assertion.

![Funnel of 448 attested security key registrations from the Passkeys Debugger: 365 or 81% pass FIDO certified L1 or higher, of which 188 are L2. Rejected: 71 not in MDS, 8 in MDS but not certified, 4 with a chain that does not reach the MDS root](https://www.corbado.com/website-assets/fido_certified_mds_check_v4_acd833c2a1.png "rounded")

### 5.1 Who fails, and why

Most rejections are correct: hobby and open-source keys, small vendors without metadata,
and older U2F keys whose key IDs were never listed. Phones used over QR code are not
security keys and are excluded from these numbers. The rejections that hurt are timing problems. A new key generation
gets a new AAGUID, and the server only knows it once the Metadata Service lists it. Two
YubiKey registrations with firmware 6.0 in our data were not in our October snapshot.

### 5.2 Require L1, not L2

The same model can sit at two levels: YubiKey 5 Series with NFC appears 85 times as L1 and
49 times as L2 in our data, because each firmware generation has its own AAGUID and its own
certification. Requiring L2 would have rejected another 40% of all registrations, most of them
genuine YubiKeys.

### 5.3 Without the Metadata Service

A hand-kept allow list of AAGUIDs, key IDs and manufacturer roots works, but it is a frozen
copy of the Metadata Service. It misses new certifications, new firmware AAGUIDs and above
all revocations. The Metadata Service itself is free: a signed BLOB that the server
downloads, verifies and refreshes about once a month.

## 6. Prerequisites for AAL3 security keys

Sections 2 to 5 boil down to one list. The first two checks are part of every WebAuthn
server; the policy checks decide whether "FIDO Certified" and "hardware only" actually hold
for your rollout:

![Registration checks for an AAL3 security key: challenge, origin and RP ID; user present; not synced (backup eligible false); attestation verified; model certified; status clean; not registered twice; recovery planned](https://www.corbado.com/website-assets/registration_checks_aal3_card_46b62d6e59.png "rounded")

### 6.1 Checks at registration

- **Ask for the right credential:** U2F-style or passkey, plus `attestation: "direct"` and
  the hint `"security-key"`. Use `"discouraged"` or `"required"`; with `"preferred"` check
  the user verified flag and classify the key (section 2.4).
- **Reject synced passkeys:** the backup eligible flag (BE) must be 0. Password manager
  extensions intercept U2F-style registrations too.
- **Verify the attestation:** `packed` and `fido-u2f`, chain to the manufacturer root. For
  Yubico that means trusting both the older root and the newer root used from firmware 5.7.
- **Check certification and status** in the Metadata Service, L1 or higher, no revocation.
  L1 also covers software authenticators, so for AAL3 also check that the metadata's
  `keyProtection` says hardware or secure element.
- **Store per key:** model, format, AAGUID or key ID, certification level and registration
  date, so you can find every affected customer when a model is revoked later.
- **Explain the Chrome prompt** that asks to share the key's make and model, or customers
  decline it and the key gets rejected.

### 6.2 Operations and recovery

- **Plan recovery:** let customers register a second key and define the re-verification
  path for a lost key before launch.
- **Keep the metadata current:** reload the Metadata Service monthly and re-check stored
  keys against new revocations.
- **Decide passkeys on keys separately:** they need the PIN, and a forgotten PIN means a
  reset of the key.

### 6.3 What identity platforms offer

Not every identity platform exposes these checks. Some offer a minimum FIDO certification
level backed by the Metadata Service as a setting, others only collect the attestation and
leave the evaluation to you. Ask your vendor four questions: does it verify `packed` and
`fido-u2f`, can it require a certification level, can it reject BE=1 and can it keep an
allow list by AAGUID and key ID?

## 7. How Corbado can help

The [Passkeys Debugger](https://www.passkeys-debugger.io) runs every check from this article
on your own key: it decodes the attestation, names the model by AAGUID or certificate key
ID, checks the chain and certification against the FIDO Metadata Service and shows the user
present, user verified and backup flags. The presets for the
[U2F-style](https://www.passkeys-debugger.io/?preset=create-u2f-style-security-key-only) and
[passkey](https://www.passkeys-debugger.io/?preset=create-security-key-only) setups reproduce
both uses in one click, and the [second factor guide](https://www.passkeys-debugger.io/how-to/security-key-second-factor) explains how to read the result.

In production, Corbado Observe shows the same signals across your real users: which keys
register, in which format, where a PIN prompt appears and where customers drop off. That is
the data you need to decide whether a stricter policy is worth the friction.

## 8. Conclusion

Both setups can support AAL3 when the authenticator and the complete authentication process
meet the applicable NIST requirements. Attestation and metadata help verify the
authenticator's properties, and attestation arrives in two formats that the server has to
handle equally. "FIDO Certified" is a concrete Metadata Service check with a sensible minimum
of L1, but FIDO certification alone does not establish AAL3 compliance. And "discouraged" user verification is a wish that Windows and some
keys ignore, so the PIN belongs in your test plan and your support scripts.

## Frequently Asked Questions

### Is a security key as a second factor AAL3?

It can be. NIST SP 800-63B-4 allows a password combined with a single-factor cryptographic
device at AAL3, and the touch on the key provides the required authentication intent. The key
must hold a non-exportable private key, which the server confirms through attestation and
metadata, and the complete authentication process must meet NIST's other AAL3 requirements,
such as FIPS 140 validation and reauthentication limits.

### Why does my security key return fido-u2f instead of packed?

The browser talked to the key over the old U2F protocol. Chrome does that for
non-discoverable registrations when a CTAP 2.0 key has a PIN set, to avoid an unnecessary
PIN prompt. CTAP 2.1 keys usually return `packed`. Your server should accept both.

### Why does Windows ask for my security key PIN although the site said discouraged?

On Windows the browser hands security keys to Windows' own WebAuthn API, which shows its own
dialog. Chrome's trick of falling back to the old U2F protocol is not available there, so an
older CTAP 2.0 key with a PIN set will typically ask for it. Test Windows separately and make sure
customers know their key's PIN.

### Can I check FIDO certification without the Metadata Service?

Only with a hand-kept allow list of AAGUIDs, certificate key IDs and manufacturer roots. That
list misses new certifications, new firmware and revocations, so the Metadata Service is the
better source.

### Which certification level should a bank require?

L1, combined with a metadata check for hardware key protection. Higher levels reject many
genuine keys, because certification is tracked per firmware generation and many keys in use
carry L1. L1 alone does not prove hardware protection, since it also covers software
authenticators.
