-
Notifications
You must be signed in to change notification settings - Fork 38
Description
Description:
When using the Okta gem for OmniAuth OAuth integration, I encountered an issue where the state parameter sent in the initial authorization request was overridden by a random state generated by the gem. This happened because the omniauth-oauth2 gem, which the Okta gem relies on, has a method in lib/omniauth/strategies/oauth2.rb that sets state to a random value:
def authorize_params # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
options.authorize_params[:state] = SecureRandom.hex(24)
....
end
As a result, the callback returned a different state than what I originally sent, which broke functionality that relied on the exact value of state. The state parameter is essential for maintaining the integrity of the request, ensuring CSRF protection, and properly handling OAuth callbacks.
Solution:
I found a workaround by creating an initializer to override the authorize_params method and ensure the state is returned as it was originally sent:
class OmniAuth::Strategies::Okta < OmniAuth::Strategies::OAuth2
option :authorize_options, %i[scope state]
def authorize_params
super.tap do |params|
options[:authorize_options].each do |k|
params[k] = request.params[k.to_s] if request.params[k.to_s].present?
end
session["omniauth.state"] = params[:state] if params[:state].present?
end
end
end
Additionally, this approach allows other parameters to be passed by adding them to authorize_options.
Key points:
- Including
scopeinauthorize_optionsis necessary to avoid returning nil values. - Storing the
statein the session withsession["omniauth.state"] = params[:state]is required to prevent CSRF errors. - This solution also allows you to pass other parameters, such as
login_hint, by adding them toauthorize_options, enhancing the flexibility of your OAuth flow.