Files
fizzy/lib/action_pack/passkey/challenges_controller.rb
2026-03-25 17:57:37 +01:00

50 lines
1.7 KiB
Ruby

# = Action Pack Passkey Challenges Controller
#
# Generates fresh WebAuthn challenges for passkey ceremonies. The companion
# JavaScript calls this endpoint before initiating a registration or
# authentication ceremony so that the challenge is issued just-in-time rather
# than embedded in the initial page load.
#
# The generated challenge is returned in the JSON response body. The challenge
# is a signed, expiring token that the server can verify on the subsequent
# form submission without needing server-side state — the challenge is
# extracted from the authenticator's +clientDataJSON+ response.
#
# == Route
#
# By default mounted at +/rails/action_pack/passkey/challenge+ (configurable
# via +config.action_pack.passkey.routes_prefix+).
#
class ActionPack::Passkey::ChallengesController < ActionController::Base
include ActionPack::Passkey::Request
# Generates a fresh challenge and returns it as JSON. Accepts an optional
# +purpose+ parameter ("registration" or "authentication") to select the
# appropriate challenge expiration. Defaults to "authentication".
def create
render json: { challenge: create_passkey_challenge }
end
private
def create_passkey_challenge
ActionPack::WebAuthn::PublicKeyCredential::Options.new(
challenge_expiration: challenge_expiration,
challenge_purpose: challenge_purpose
).challenge
end
def challenge_purpose
params[:purpose] == "registration" ? "registration" : "authentication"
end
def challenge_expiration
config = Rails.configuration.action_pack.web_authn
if challenge_purpose == "registration"
config.creation_challenge_expiration
else
config.request_challenge_expiration
end
end
end