@@ -56,32 +56,14 @@ def authorize
5656 code_challenge = params [ :code_challenge ]
5757 code_challenge_method = params [ :code_challenge_method ] || "plain"
5858
59- # Validate required parameters
60- unless client_id . present? && redirect_uri . present? && response_type == "code"
61- error_details = [ ]
62- error_details << "client_id is required" unless client_id . present?
63- error_details << "redirect_uri is required" unless redirect_uri . present?
64- error_details << "response_type must be 'code'" unless response_type == "code"
65-
66- render plain : "Invalid request: #{ error_details . join ( ", " ) } " , status : :bad_request
59+ # Validate client_id first (required before we can look up the application)
60+ # OAuth2 RFC 6749 Section 4.1.2.1: If client_id is missing/invalid, show error page (don't redirect)
61+ unless client_id . present?
62+ render plain : "Invalid request: client_id is required" , status : :bad_request
6763 return
6864 end
6965
70- # Validate PKCE parameters if present
71- if code_challenge . present?
72- unless %w[ plain S256 ] . include? ( code_challenge_method )
73- render plain : "Invalid code_challenge_method: must be 'plain' or 'S256'" , status : :bad_request
74- return
75- end
76-
77- # Validate code challenge format (base64url-encoded, 43-128 characters)
78- unless code_challenge . match? ( /\A [A-Za-z0-9\- _]{43,128}\z / )
79- render plain : "Invalid code_challenge format: must be 43-128 characters of base64url encoding" , status : :bad_request
80- return
81- end
82- end
83-
84- # Find the application
66+ # Find the application by client_id
8567 @application = Application . find_by ( client_id : client_id , app_type : "oidc" )
8668 unless @application
8769 # Log all OIDC applications for debugging
@@ -99,7 +81,14 @@ def authorize
9981 return
10082 end
10183
102- # Validate redirect URI first (required before we can safely redirect with errors)
84+ # Validate redirect_uri presence and format
85+ # OAuth2 RFC 6749 Section 4.1.2.1: If redirect_uri is missing/invalid, show error page (don't redirect)
86+ unless redirect_uri . present?
87+ render plain : "Invalid request: redirect_uri is required" , status : :bad_request
88+ return
89+ end
90+
91+ # Validate redirect URI matches one of the registered URIs
10392 unless @application . parsed_redirect_uris . include? ( redirect_uri )
10493 Rails . logger . error "OAuth: Invalid request - redirect URI mismatch. Expected: #{ @application . parsed_redirect_uris } , Got: #{ redirect_uri } "
10594
@@ -114,6 +103,44 @@ def authorize
114103 return
115104 end
116105
106+ # ============================================================================
107+ # At this point we have a valid client_id and redirect_uri
108+ # All subsequent errors should redirect back to the client with error parameters
109+ # per OAuth2 RFC 6749 Section 4.1.2.1
110+ # ============================================================================
111+
112+ # Validate response_type (now we can safely redirect with error)
113+ unless response_type == "code"
114+ Rails . logger . error "OAuth: Invalid response_type: #{ response_type } "
115+ error_uri = "#{ redirect_uri } ?error=unsupported_response_type"
116+ error_uri += "&error_description=#{ CGI . escape ( "Only 'code' response_type is supported" ) } "
117+ error_uri += "&state=#{ CGI . escape ( state ) } " if state . present?
118+ redirect_to error_uri , allow_other_host : true
119+ return
120+ end
121+
122+ # Validate PKCE parameters if present (now we can safely redirect with error)
123+ if code_challenge . present?
124+ unless %w[ plain S256 ] . include? ( code_challenge_method )
125+ Rails . logger . error "OAuth: Invalid code_challenge_method: #{ code_challenge_method } "
126+ error_uri = "#{ redirect_uri } ?error=invalid_request"
127+ error_uri += "&error_description=#{ CGI . escape ( "Invalid code_challenge_method: must be 'plain' or 'S256'" ) } "
128+ error_uri += "&state=#{ CGI . escape ( state ) } " if state . present?
129+ redirect_to error_uri , allow_other_host : true
130+ return
131+ end
132+
133+ # Validate code challenge format (base64url-encoded, 43-128 characters)
134+ unless code_challenge . match? ( /\A [A-Za-z0-9\- _]{43,128}\z / )
135+ Rails . logger . error "OAuth: Invalid code_challenge format"
136+ error_uri = "#{ redirect_uri } ?error=invalid_request"
137+ error_uri += "&error_description=#{ CGI . escape ( "Invalid code_challenge format: must be 43-128 characters of base64url encoding" ) } "
138+ error_uri += "&state=#{ CGI . escape ( state ) } " if state . present?
139+ redirect_to error_uri , allow_other_host : true
140+ return
141+ end
142+ end
143+
117144 # Check if application is active (now we can safely redirect with error)
118145 unless @application . active?
119146 Rails . logger . error "OAuth: Application is not active: #{ @application . name } "
0 commit comments