Class: Passkeyed::Configuration
- Inherits:
-
Object
- Object
- Passkeyed::Configuration
- Defined in:
- lib/passkeyed/configuration.rb,
sig/passkeyed/configuration.rbs
Overview
Holds passkeyed's settings. The relevant ones are handed to webauthn-ruby
as an isolated WebAuthn::RelyingParty (see relying_party), never written
to WebAuthn's global configuration.
Passkeyed.configure do |config|
config.rp_name = "Acme"
config.rp_id = "acme.example" # optional
config.allowed_origins = ["https://acme.example"] # required when deployed
config.user_verification = "required"
end
Constant Summary collapse
- USER_VERIFICATION_LEVELS =
The WebAuthn userVerification enum. We normalize to these exact strings so the value advertised to the client and the value enforced server-side can never diverge (a symbol or mis-cased string would silently disable enforcement while still advertising "required").
%w[required preferred discouraged].freeze
Instance Attribute Summary collapse
-
#allowed_origins ⇒ Array[String]?
Array of origins the server will accept assertions from, e.g.
-
#challenge_timeout ⇒ Integer
How long (in seconds) a stashed challenge stays valid.
-
#rp_id ⇒ String?
The relying party id (effectively your domain).
-
#rp_name ⇒ String
Human-readable name of the relying party (your app), shown by some authenticators during the ceremony.
-
#session_key ⇒ Symbol
Base session key from which the per-ceremony challenge keys are derived (see
registration_challenge_key/authentication_challenge_key). -
#user_verification ⇒ String
User-verification requirement for both ceremonies.
Instance Method Summary collapse
- #authentication_challenge_key ⇒ Symbol
-
#enforce_secure_origins? ⇒ Boolean
True in any deployed environment: everything except Rails.env.local? (development and test, per Rails >= 7.1 — the gem's declared floor).
-
#initialize ⇒ Configuration
constructor
A new instance of Configuration.
-
#registration_challenge_key ⇒ Symbol
Distinct session keys for the two ceremonies, derived from
session_key. -
#relying_party ⇒ Object
WebAuthn::RelyingParty (webauthn-ruby ships no RBS, so left untyped).
-
#validate! ⇒ void
Refuse to boot a deployed app with development origins.
Constructor Details
#initialize ⇒ Configuration
Returns a new instance of Configuration.
52 53 54 55 56 57 58 59 |
# File 'lib/passkeyed/configuration.rb', line 52 def initialize @rp_name = "Passkeyed" @rp_id = nil @allowed_origins = nil self.user_verification = "required" @session_key = :passkeyed_challenge self.challenge_timeout = 300 end |
Instance Attribute Details
#allowed_origins ⇒ Array[String]?
Array of origins the server will accept assertions from, e.g.
["https://acme.example"]. Left nil only for local development; required
(https-only) in any deployed environment — see validate!.
32 33 34 |
# File 'lib/passkeyed/configuration.rb', line 32 def allowed_origins @allowed_origins end |
#challenge_timeout ⇒ Integer
How long (in seconds) a stashed challenge stays valid. A ceremony should complete within moments; a challenge consumed hours after it was issued points at a stale tab or a replay attempt, so it is rejected with Passkeyed::ChallengeExpired. Also advertised to the browser as the ceremony timeout (via the relying party), so the credential prompt and the server agree on the lifetime. Read via the accessor; always a positive Integer (see the writer).
50 51 52 |
# File 'lib/passkeyed/configuration.rb', line 50 def challenge_timeout @challenge_timeout end |
#rp_id ⇒ String?
The relying party id (effectively your domain). When nil, webauthn-ruby derives it from the request origin.
27 28 29 |
# File 'lib/passkeyed/configuration.rb', line 27 def rp_id @rp_id end |
#rp_name ⇒ String
Human-readable name of the relying party (your app), shown by some authenticators during the ceremony.
23 24 25 |
# File 'lib/passkeyed/configuration.rb', line 23 def rp_name @rp_name end |
#session_key ⇒ Symbol
Base session key from which the per-ceremony challenge keys are derived
(see registration_challenge_key / authentication_challenge_key).
41 42 43 |
# File 'lib/passkeyed/configuration.rb', line 41 def session_key @session_key end |
#user_verification ⇒ String
User-verification requirement for both ceremonies. "required" is what makes a single passkey gesture genuinely multi-factor. Read via the accessor; always one of USER_VERIFICATION_LEVELS (see the writer).
37 38 39 |
# File 'lib/passkeyed/configuration.rb', line 37 def user_verification @user_verification end |
Instance Method Details
#authentication_challenge_key ⇒ Symbol
100 101 102 |
# File 'lib/passkeyed/configuration.rb', line 100 def authentication_challenge_key :"#{session_key}_authentication" end |
#enforce_secure_origins? ⇒ Boolean
True in any deployed environment: everything except Rails.env.local? (development and test, per Rails >= 7.1 — the gem's declared floor).
149 150 151 |
# File 'lib/passkeyed/configuration.rb', line 149 def enforce_secure_origins? defined?(Rails) && Rails.respond_to?(:env) && !Rails.env.local? end |
#registration_challenge_key ⇒ Symbol
Distinct session keys for the two ceremonies, derived from session_key.
Keeping them separate means a registration and an authentication ceremony
running concurrently in the same session (a background tab, a stale form)
can't overwrite each other's single-use challenge.
96 97 98 |
# File 'lib/passkeyed/configuration.rb', line 96 def registration_challenge_key :"#{session_key}_registration" end |
#relying_party ⇒ Object
WebAuthn::RelyingParty (webauthn-ruby ships no RBS, so left untyped).
109 110 111 112 113 114 115 116 117 118 |
# File 'lib/passkeyed/configuration.rb', line 109 def WebAuthn::RelyingParty.new( name: rp_name, id: rp_id, allowed_origins: allowed_origins, # Also advertised to the browser as the ceremony timeout, so the # credential prompt can't outlive the server-side challenge. credential_options_timeout: challenge_timeout * 1000 ) end |
#validate! ⇒ void
This method returns an undefined value.
Refuse to boot a deployed app with development origins. WebAuthn requires a secure context, so a blank allow-list or an http:// origin outside development and test is always a misconfiguration — most often the generated localhost default left in place. Fail loud at boot rather than silently rejecting every sign-in (or, worse, trusting an insecure origin). Runs in every non-local environment (production, staging, any custom deploy env); no-op in development/test and when Rails isn't loaded (e.g. the gem's own suite).
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/passkeyed/configuration.rb', line 128 def validate! return unless enforce_secure_origins? if allowed_origins.blank? raise Passkeyed::ConfigurationError, "allowed_origins is required outside development and test; " \ "set config.allowed_origins to your HTTPS origin(s)" end insecure = allowed_origins.reject { |origin| origin.to_s.start_with?("https://") } return if insecure.empty? raise Passkeyed::ConfigurationError, "allowed_origins must use https outside development and test; got #{insecure.inspect} " \ "(the generated localhost default cannot be used in a deployed environment)" end |