# `@teamhanko/hanko-webauthn`

`@teamhanko/hanko-webauthn` is a client-side Javascript library that serves as a wrapper for the 
[WebAuthn API](https://www.w3.org/TR/webauthn/) by encoding binary data using 
[base64url](https://w3c.github.io/webauthn/#sctn-dependencies) (also known as "websafe" or "urlsafe" base64).

The WebAuthn API itself takes input and output values that look almost like JSON, except that binary data is represented
as `ArrayBuffer`s. Using `hanko-webauthn` allows the data to be sent from/to the server as normal JSON without any custom
client-side processing.

## Installation

### NPM/Yarn

```shell
# Using npm
npm install --save @teamhanko/hanko-webauthn

# Using yarn
yarn add @teamhanko/hanko-webauthn
```

### CDN

Alternatively, you can load the library via CDN using a script tag in your application `<head>`:

```html
<script src="https://cdn.jsdelivr.net/npm/@teamhanko/hanko-webauthn@latest/dist/browser-global/hanko-webauthn.browser-global.js"></script>
```

When using this method a browser global `hankoWebAuthn` will be set.

```javascript
// destructure global
const { create: createCredentials, get: getCredentials } = hankoWebAuthn;

// using the global directly
hankoWebAuthn.create();
```

## Usage

The following are simple examples for performing registration and authentication using the SDK . 
For more information, refer to the Hanko API [implementation guide](https://docs.hanko.io/implementation/introduction).

### Registration

```javascript
import {create as createCredential} from "@teamhanko/hanko-webauthn"

// register credential for a given userName, which typically would be read from
// a registration form
async function register(userName) {
  try {
    const credentialCreationOptions = await initializeRegistration(userName);
    const webAuthnResponse = await createCredential(credentialCreationOptions);
    return await finalizeRegistration(webAuthnResponse)
  } catch (error) {
    // handle error
  }
}

// retrieve credential creation options to pass to the WebAuthn API
async function initializeRegistration(userName) {
  // adjust fetch URL to backend handler for retrieving 
  // credential creation options from FIDO server
  const response = await fetch(`/webauthn/registration/initialize?user_name=${userName}`);

  if (!response.ok) {
    // handle fetch error
  }

  return response.json();
}

// verify WebAuthn response
async function finalizeRegistration(webAuthnResponse) {
  // adjust fetch URL to backend handler for verifying 
  // WebAuthn response with FIDO server
  const response = await fetch('/webauthn/registration/finalize', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify(webAuthnResponse)
  });

  if (!response.ok) {
    // handle fetch error
  }

  return response.json();
}
```

### Authentication

```javascript
import {get as getCredential} from "@teamhanko/hanko-webauthn"

// authenticate with a credential for a given userName, which typically would be read from
// a login form
async function authenticate(userName) {
  try {
    const credentialRequestOptions = await initializeAuthentication(userName);
    const credential = await getCredential(credentialRequestOptions);
    return await finalizeAuthentication(credential)
  } catch (error) {
    // handle error
  }
}

// retrieve credential request options to pass to the WebAuthn API
async function initializeAuthentication(userName) {
  // adjust fetch URL to backend handler for retrieving 
  // credential request options from FIDO server
  const response = await fetch(`/webauthn/authentication/initialize?user_name=${userName}`);

  if (!response.ok) {
    // handle fetch error
  }

  return response.json()
}

// verify WebAuthn response
async function finalizeAuthentication(webAuthnResponse) {
  // adjust fetch URL to backend handler for verifying 
  // WebAuthn response with FIDO server
  const response = await fetch("/webauthn/authentication/finalize", {
    method: 'POST',
    headers: {'Content-Type': 'application/json'}, 
    body: JSON.stringify(webAuthnResponse)
  });

  if (!response.ok) {
    // handle fetch error
  }

  return response.json();
}
```

### API

```typescript
function create(requestJSON: CredentialCreationOptionsJSON): Promise<PublicKeyCredentialWithAttestationJSON>;
function get(requestJSON: CredentialRequestOptionsJSON): Promise<PublicKeyCredentialWithAssertionJSON>;
function supported(): boolean;
function isUserVerifyingPlatformAuthenticatorAvailable: Promise<boolean>;
function isSecurityKeySupported(): Promise<boolean>;
```

- `create(requestJSON: CredentialCreationOptionsJSON): Promise<PublicKeyCredentialWithAttestationJSON>`:
    - **Description**: Request the creation of a new credential bound to an authenticator.
      - **Parameters**:
        - `requestJSON`: 
            - Type: `CredentialCreationOptionsJSON`
                - `publicKey`: 
                  - Type: [PublicKeyCredentialCreationOptions](https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialcreationoptions)
                - `signal`: 
                  - Type: [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
                  - See also: [Aborting Authentication Operations](https://www.w3.org/TR/webauthn/#sctn-sample-aborting)
    - **Returns**: Promise that resolves to a `PublicKeyCredentialWithAttestationJSON`
      (a [PublicKeyCredential](https://www.w3.org/TR/webauthn/#iface-pkcredential) representation, whose `response`
      value is an [AuthenticatorAttestationResponse](https://www.w3.org/TR/webauthn/#authenticatorattestationresponse))
    - **See also**: [Web Authentication:
      An API for accessing Public Key Credentials - Create credential](https://www.w3.org/TR/webauthn/#sctn-createCredential)

- `get(requestJSON: CredentialRequestOptionsJSON): Promise<PublicKeyCredentialWithAssertionJSON>`:
    - **Description**: Discover and use an existing credential on an authenticator.
    - **Parameters**:
        - Type: `CredentialRequestOptionsJSON`
          - `publicKey`:
            - Type: [PublicKeyCredentialRequestOptions](https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions)
          - `signal`: 
            - Type: [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
            - See also: [Aborting Authentication Operations](https://www.w3.org/TR/webauthn/#sctn-sample-aborting)
    - **Returns**: Promise that resolves to a `PublicKeyCredentialWithAssertionJSON`
      (a [PublicKeyCredential](https://www.w3.org/TR/webauthn/#iface-pkcredential) representation, whose `response`
      value is an [AuthenticatorAssertionResponse](https://www.w3.org/TR/webauthn/#authenticatorassertionresponse))
    - **See also**: [Web Authentication:
      An API for accessing Public Key Credentials - Get assertion](https://www.w3.org/TR/webauthn/#sctn-getAssertion)

- `supported(): boolean`:
    - **Description**: Check if the browser supports the Web Authentication API.

- `isUserVerifyingPlatformAuthenticatorAvailable(): Promise<boolean>`:
    - **Description**: Check if a user verifying platform authenticator is available.

- `isSecurityKeySupported(): Promise<boolean>`:
    - **Description**: In Firefox, checks if external CTAP2 security keys are supported, does a `supported()`
      check in any other browser.

## Acknowledgements

`@teamhanko/hanko-webauthn` is a fork of the [`@github/webauthn-json`](https://github.com/github/webauthn-json) library.
