# Web Authentication API (WebAuthn)

The Web Authentication API (WebAuthn) enables passwordless authentication using public key cryptography. It allows users to log in using biometrics (TouchID, FaceID), mobile devices, or security keys (YubiKey), which is far more secure than passwords.

## 1. The Concept

WebAuthn replaces passwords with a private/public key pair.
*   **Private Key:** Stored securely on the user's device (Authenticator). It never leaves the device.
*   **Public Key:** Sent to the server (Relying Party).

To log in, the server sends a "challenge". The device signs it with the private key. The server verifies the signature with the public key.

## 2. Registration (Sign Up)

To register a new credential, you use `navigator.credentials.create()`.

1.  **Server:** Generates a random challenge and user info.
2.  **Client:** Calls `create()` with this info.
3.  **Authenticator:** Asks user for consent (fingerprint/pin), generates keys, and signs the challenge.
4.  **Client:** Sends the new public key and attestation to the server.

```javascript
// Options usually come from the server
const publicKeyCredentialCreationOptions = {
    challenge: Uint8Array.from("random_challenge_from_server", c => c.charCodeAt(0)),
    rp: {
        name: "My App",
        id: "example.com",
    },
    user: {
        id: Uint8Array.from("user_id", c => c.charCodeAt(0)),
        name: "john.doe@example.com",
        displayName: "John Doe",
    },
    pubKeyCredParams: [{ alg: -7, type: "public-key" }], // -7 is ES256
    authenticatorSelection: {
        authenticatorAttachment: "platform", // "platform" (TouchID) or "cross-platform" (YubiKey)
    },
    timeout: 60000,
    attestation: "direct"
};

async function registerUser() {
    try {
        const credential = await navigator.credentials.create({
            publicKey: publicKeyCredentialCreationOptions
        });
        
        console.log("Credential created:", credential);
        // Send credential to server for verification and storage
    } catch (err) {
        console.error("Registration failed:", err);
    }
}
```

## 3. Authentication (Login)

To log in, you use `navigator.credentials.get()`.

1.  **Server:** Generates a challenge.
2.  **Client:** Calls `get()` with the challenge.
3.  **Authenticator:** Asks for consent, signs the challenge using the stored private key.
4.  **Client:** Sends the signature to the server.
5.  **Server:** Verifies the signature using the stored public key.

```javascript
// Options usually come from the server
const publicKeyCredentialRequestOptions = {
    challenge: Uint8Array.from("random_challenge_from_server", c => c.charCodeAt(0)),
    timeout: 60000,
    // Optional: List of allowed credentials (if you know who the user is trying to be)
    allowCredentials: [
        {
            id: Uint8Array.from("credential_id", c => c.charCodeAt(0)),
            type: "public-key",
            transports: ["internal"],
        }
    ],
};

async function loginUser() {
    try {
        const assertion = await navigator.credentials.get({
            publicKey: publicKeyCredentialRequestOptions
        });
        
        console.log("Assertion received:", assertion);
        // Send assertion to server for verification
    } catch (err) {
        console.error("Login failed:", err);
    }
}
```

## 4. Server-Side Requirement

WebAuthn is **not** a client-side only API. It requires a server to:
1.  Generate unique challenges (to prevent replay attacks).
2.  Store public keys and credential IDs.
3.  Verify cryptographic signatures.

## 5. Browser Support

WebAuthn is supported in all modern browsers. However, it requires a **Secure Context** (HTTPS or localhost).

[[programming/javascript/vanilla/javascript]]
[[programming/javascript/vanilla/promises-async-await]]
[[programming/javascript/vanilla/typed-arrays]]