Class: Unmagic::Passkeys::WebAuthn::PublicKeyCredential

Inherits:
Object
  • Object
show all
Defined in:
lib/unmagic/passkeys/web_authn/public_key_credential.rb

Overview

Action Pack WebAuthn Public Key Credential

Represents a WebAuthn public key credential and orchestrates the registration and authentication ceremonies. During registration (.register), it verifies the attestation response and returns a new credential. During authentication (#authenticate), it verifies the assertion response against the stored public key.

Registration

credential = Unmagic::Passkeys::WebAuthn::PublicKeyCredential.register(
  params[:passkey],
  origin: Unmagic::Passkeys::WebAuthn::Current.origin
)

credential.id         # => Base64URL-encoded credential ID
credential.public_key # => OpenSSL::PKey::EC
credential.sign_count # => 0

Authentication

credential = Unmagic::Passkeys::WebAuthn::PublicKeyCredential.new(
  id: stored_credential_id,
  public_key: stored_public_key,
  sign_count: stored_sign_count
)

credential.authenticate(params[:passkey])

Ceremony Options

Use .creation_options and .request_options to generate the JSON options passed to the browser’s navigator.credentials.create() and navigator.credentials.get() calls.

Attributes

id

The Base64URL-encoded credential identifier.

public_key

The OpenSSL public key for signature verification.

sign_count

The signature counter, used for replay detection.

aaguid

The authenticator attestation GUID (set during registration).

backed_up

Whether the credential is backed up to cloud storage (synced passkey).

transports

Transport hints (e.g., “internal”, “usb”, “ble”, “nfc”).

Defined Under Namespace

Classes: CreationOptions, Options, RequestOptions

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id:, public_key:, sign_count:, aaguid: nil, backed_up: nil, transports: []) ⇒ PublicKeyCredential

Returns a new instance of PublicKeyCredential.



113
114
115
116
117
118
119
120
121
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 113

def initialize(id:, public_key:, sign_count:, aaguid: nil, backed_up: nil, transports: [])
  @id = id
  @public_key = public_key
  @public_key = OpenSSL::PKey.read(public_key) unless public_key.is_a?(OpenSSL::PKey::PKey)
  @sign_count = sign_count
  @aaguid = aaguid
  @backed_up = backed_up
  @transports = transports
end

Instance Attribute Details

#aaguidObject (readonly)

Returns the value of attribute aaguid.



57
58
59
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 57

def aaguid
  @aaguid
end

#backed_upObject (readonly)

Returns the value of attribute backed_up.



57
58
59
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 57

def backed_up
  @backed_up
end

#idObject (readonly)

Returns the value of attribute id.



57
58
59
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 57

def id
  @id
end

#public_keyObject (readonly)

Returns the value of attribute public_key.



57
58
59
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 57

def public_key
  @public_key
end

#sign_countObject (readonly)

Returns the value of attribute sign_count.



57
58
59
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 57

def sign_count
  @sign_count
end

#transportsObject (readonly)

Returns the value of attribute transports.



57
58
59
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 57

def transports
  @transports
end

Class Method Details

.creation_options(**attributes) ⇒ Object

Returns a CreationOptions object for the registration ceremony. Credentials in exclude_credentials responding to to_public_key_credential are automatically transformed.



72
73
74
75
76
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 72

def creation_options(**attributes)
  attributes[:exclude_credentials] = transform_credentials(attributes[:exclude_credentials]) if attributes[:exclude_credentials]

  Unmagic::Passkeys::WebAuthn::PublicKeyCredential::CreationOptions.new(**attributes)
end

.register(params, origin: Unmagic::Passkeys::WebAuthn::Current.origin) ⇒ Object

Verifies an attestation response from the browser and returns a new PublicKeyCredential with the registered credential data.

Raises InvalidResponseError if the attestation is invalid.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 82

def register(params, origin: Unmagic::Passkeys::WebAuthn::Current.origin)
  response = Unmagic::Passkeys::WebAuthn::Authenticator::AttestationResponse.new(
    client_data_json: params[:client_data_json],
    attestation_object: params[:attestation_object],
    origin: origin
  )

  response.validate!

  new(
    id: response.attestation.credential_id,
    public_key: response.attestation.public_key,
    sign_count: response.attestation.sign_count,
    aaguid: response.attestation.aaguid,
    backed_up: response.attestation.backed_up?,
    transports: Array(params[:transports])
  )
end

.request_options(**attributes) ⇒ Object

Returns a RequestOptions object for the authentication ceremony. Credentials responding to to_public_key_credential are automatically transformed.



63
64
65
66
67
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 63

def request_options(**attributes)
  attributes[:credentials] = transform_credentials(attributes[:credentials]) if attributes[:credentials]

  Unmagic::Passkeys::WebAuthn::PublicKeyCredential::RequestOptions.new(**attributes)
end

Instance Method Details

#authenticate(params, origin: Unmagic::Passkeys::WebAuthn::Current.origin) ⇒ Object

Verifies an assertion response against this credential’s public key. Updates sign_count and backed_up on success.

Raises InvalidResponseError if the assertion is invalid.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 127

def authenticate(params, origin: Unmagic::Passkeys::WebAuthn::Current.origin)
  response = Unmagic::Passkeys::WebAuthn::Authenticator::AssertionResponse.new(
    client_data_json: params[:client_data_json],
    authenticator_data: params[:authenticator_data],
    signature: params[:signature],
    credential: self,
    origin: origin
  )

  response.validate!

  @sign_count = response.authenticator_data.sign_count
  @backed_up = response.authenticator_data.backed_up?
end

#to_hObject

Returns a Hash of the credential data suitable for persisting.



143
144
145
146
147
148
149
150
151
152
# File 'lib/unmagic/passkeys/web_authn/public_key_credential.rb', line 143

def to_h
  {
    credential_id: id,
    public_key: public_key.to_der,
    sign_count: sign_count,
    aaguid: aaguid,
    backed_up: backed_up,
    transports: transports
  }
end