/elixir-web_authn_lite

W3C Web Authentication API (a.k.a. WebAuthN / FIDO 2.0) RP library in Elixir

Primary LanguageElixirMIT LicenseMIT

WebAuthnLite

W3C Web Authentication API (a.k.a. WebAuthN / FIDO 2.0) RP library in Elixir

Installation

If available in Hex, the package can be installed by adding web_authn_lite to your list of dependencies in mix.exs:

def deps do
  [
    {:web_authn_lite, "~> 0.1.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/web_authn_lite.

Usage : 1. Registration

1.1. Generate and store challenge

Server-side

challenge = WebAuthnLite.Challenge.generate_base64_url_encoded_challenge()

conn
|> put_session(:webauthn_register_challenge, challenge) # for phenix etc...
...

1.2. Request WebAuthn registration

Client-side

Set Base64 URL decoded challenge and call navigator.credentials.create()

1.3. Send encoded response to Server-side

Client-side

Encode following params and send them to server-side.

  • clientDataJSON
  • attestationObject

1.4. Validate ClientDataJSON

Server-side

challenge = conn |> get_session(:webauthn_register_challenge)

{:ok, client_data_json} =
  WebAuthnLite.Operation.Register.validate_client_data_json(
    %{client_data_json: encoded_client_data_json,
      origin: origin,
      challenge: challenge
    }
  )

1.5. Validate AttestationObject

Server-side

{:ok, storable_public_key, attestation_object} = 
  WebAuthnLite.Operation.Register.validate_attestation_object(
    %{attestation_object: encoded_attestation_object,
      client_data_json: encoded_client_data_json,
      rp_id: rp_id,
      up_required: up_required,
      uv_required: uv_required})

1.6. Store Credential.Id with account

Server-side

pubkey = attestation_object.auth_data.attested_credential_data.credential_public_key

# identifier
pubkey_id = attestation_object.auth_data.attested_credential_data.credential_id

# key params
pubkey_map = pubkey.map
pubkey_json = pubkey.json

Usage : 2. Authentication

2.1. Generate and store challenge

Server-side

challenge = WebAuthnLite.Challenge.generate_base64_url_encoded_challenge()

conn
|> put_session(:webauthn_authn_challenge, challenge) # for phenix etc...
...

2.2. Request WebAuthn authentication

Client-side

Set Base64 URL decoded challenge and call navigator.credentials.get()

2.3. Send encoded response to Server-side

Client-side

Encode following params and send them to server-side.

  • clientDataJSON
  • authenticatorData
  • signature

2.4. Validate clientDataJSON

Server-side

challenge = conn |> get_session(:webauthn_authn_challenge)

{:ok, client_data_json} =
  WebAuthnLite.Operation.Authenticate.validate_client_data_json(
    %{client_data_json: encoded_client_data_json,
      origin: origin,
      challenge: challenge
    }
  )

2.5. Validate authenticatorData

{:ok, updated_storable_public_key, authenticator_data} =
  WebAuthnLite.Operation.Authenticate.validate_authenticator_assertion(
    %{credential_id: credential_id,
      signature: encoded_signature,
      authenticator_data: encoded_authenticator_data,
      client_data_json: encoded_client_data_json,
      public_keys: [storable_public_key],
      rp_id: rp_id,
      up_required: up_required,
      uv_required: uv_required})