PKCE is now default enabled. You can now create public / no-secret apps OIDC apps
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
class Application < ApplicationRecord
|
||||
has_secure_password :client_secret, validations: false
|
||||
|
||||
# Virtual attribute to control client type during creation
|
||||
# When true, no client_secret will be generated (public client)
|
||||
attr_accessor :is_public_client
|
||||
|
||||
has_one_attached :icon
|
||||
|
||||
# Fix SVG content type after attachment
|
||||
@@ -20,7 +24,7 @@ class Application < ApplicationRecord
|
||||
validates :app_type, presence: true,
|
||||
inclusion: { in: %w[oidc forward_auth] }
|
||||
validates :client_id, uniqueness: { allow_nil: true }
|
||||
validates :client_secret, presence: true, on: :create, if: -> { oidc? }
|
||||
validates :client_secret, presence: true, on: :create, if: -> { oidc? && confidential_client? }
|
||||
validates :domain_pattern, presence: true, uniqueness: { case_sensitive: false }, if: :forward_auth?
|
||||
validates :landing_url, format: { with: URI::regexp(%w[http https]), allow_nil: true, message: "must be a valid URL" }
|
||||
validates :backchannel_logout_uri, format: {
|
||||
@@ -74,6 +78,24 @@ class Application < ApplicationRecord
|
||||
app_type == "forward_auth"
|
||||
end
|
||||
|
||||
# Client type checks (for OIDC)
|
||||
def public_client?
|
||||
client_secret_digest.blank?
|
||||
end
|
||||
|
||||
def confidential_client?
|
||||
!public_client?
|
||||
end
|
||||
|
||||
# PKCE requirement check
|
||||
# Public clients MUST use PKCE (no client secret to protect auth code)
|
||||
# Confidential clients can optionally require PKCE (OAuth 2.1 recommendation)
|
||||
def requires_pkce?
|
||||
return false unless oidc?
|
||||
return true if public_client? # Always require PKCE for public clients
|
||||
require_pkce? # Check the flag for confidential clients
|
||||
end
|
||||
|
||||
# Access control
|
||||
def user_allowed?(user)
|
||||
return false unless active?
|
||||
@@ -261,13 +283,19 @@ class Application < ApplicationRecord
|
||||
|
||||
def generate_client_credentials
|
||||
self.client_id ||= SecureRandom.urlsafe_base64(32)
|
||||
# Generate and hash the client secret
|
||||
if new_record? && client_secret.blank?
|
||||
# Generate client secret only for confidential clients
|
||||
# Public clients (is_public_client checked) don't get a secret - they use PKCE only
|
||||
if new_record? && client_secret.blank? && !is_public_client_selected?
|
||||
secret = SecureRandom.urlsafe_base64(48)
|
||||
self.client_secret = secret
|
||||
end
|
||||
end
|
||||
|
||||
# Check if the user selected public client option
|
||||
def is_public_client_selected?
|
||||
ActiveModel::Type::Boolean.new.cast(is_public_client)
|
||||
end
|
||||
|
||||
def backchannel_logout_uri_must_be_https_in_production
|
||||
return unless Rails.env.production?
|
||||
return unless backchannel_logout_uri.present?
|
||||
|
||||
@@ -4,7 +4,6 @@ class OidcRefreshToken < ApplicationRecord
|
||||
belongs_to :application
|
||||
belongs_to :user
|
||||
belongs_to :oidc_access_token
|
||||
has_many :oidc_access_tokens, foreign_key: :oidc_access_token_id, dependent: :nullify
|
||||
|
||||
before_validation :generate_token_with_prefix, on: :create
|
||||
before_validation :set_expiry, on: :create
|
||||
|
||||
@@ -74,6 +74,14 @@ class User < ApplicationRecord
|
||||
totp.verify(code, drift_behind: 30, drift_ahead: 30)
|
||||
end
|
||||
|
||||
# Console/debug helper: get current TOTP code
|
||||
def console_totp
|
||||
return nil unless totp_enabled?
|
||||
|
||||
require "rotp"
|
||||
ROTP::TOTP.new(totp_secret).now
|
||||
end
|
||||
|
||||
def verify_backup_code(code)
|
||||
return false unless backup_codes.present?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user