Class: OmniAuth::Strategies::Authify

Inherits:
OAuth2
  • Object
show all
Defined in:
lib/omniauth/strategies/authify.rb

Overview

OmniAuth strategy for Authify, a self-hosted, multi-tenant identity provider implementing OpenID Connect on top of OAuth 2.0.

Since Authify is multi-tenant, both the server base URL and the organization slug are required; all endpoints (authorize, token, userinfo and JWKS) are scoped to the organization.

Examples:

Rails/Devise usage

provider :authify,
         ENV["AUTHIFY_CLIENT_ID"],
         ENV["AUTHIFY_CLIENT_SECRET"],
         site: "https://authify.example.com",
         organization: "my-org"

Sinatra usage

use OmniAuth::Builder do
  provider :authify, ENV["AUTHIFY_CLIENT_ID"], ENV["AUTHIFY_CLIENT_SECRET"],
           site: "https://authify.example.com", organization: "my-org"
end

Constant Summary collapse

DEFAULT_SCOPE =

Scopes requested when the user does not configure any

"openid profile email"

Instance Method Summary collapse

Instance Method Details

#authorize_paramsObject

Builds authorize parameters; generates and stores a nonce for this login so the returned ID token can be bound to the request.

An OIDC prompt parameter on the request phase (e.g. "consent", "login", "none") is forwarded to Authify.



125
126
127
128
129
130
131
132
133
134
# File 'lib/omniauth/strategies/authify.rb', line 125

def authorize_params
  params = super
  params[:nonce] = SecureRandom.hex(16)
  params[:leeway] = options.leeway if options.leeway
  params[:prompt] = request.params["prompt"] if request.params.key?("prompt")

  store_authorize_params(params)

  params
end

#callback_phaseObject

Completes the login: exchanges the code for tokens (via the OmniAuth::Strategies::OAuth2 machinery), verifies the ID token while building the credentials hash, and translates any validation failure into an OmniAuth invalid_credentials failure.

The OAuth2 state check is performed here first because the parent class's secure_compare raises NoMethodError (on nil) rather than failing cleanly when the callback carries a state param but no state exists in the session (stale or replayed callbacks). The parent's own check is skipped for this invocation because ours is equivalent (the same constant-time comparison) minus the crash.



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/omniauth/strategies/authify.rb', line 162

def callback_phase
  return state_failure unless callback_state_matches?

  begin
    base_ignores_state = options.provider_ignores_state
    options.provider_ignores_state = true
    super
  ensure
    options.provider_ignores_state = base_ignores_state
  end
rescue ::OmniAuth::Authify::TokenValidationError, ::OAuth2::Error, CallbackError => e
  fail!(:invalid_credentials, e)
rescue Timeout::Error, Errno::ETIMEDOUT, ::OAuth2::TimeoutError,
       ::OAuth2::ConnectionError => e
  fail!(:timeout, e)
rescue SocketError => e
  fail!(:failed_to_connect, e)
end

#clientObject

Configure the underlying OAuth2 client URLs for the organization.



63
64
65
66
67
68
69
70
71
72
# File 'lib/omniauth/strategies/authify.rb', line 63

def client
  validate_configuration!

  base = org_base
  options.client_options.site = base
  options.client_options.authorize_url = "#{base}/oauth/authorize"
  options.client_options.token_url = "#{base}/oauth/token"

  super
end

#request_phaseArray

Initiates the authorization redirect after validating configuration.

Returns:

  • (Array)

    a Rack redirect response to Authify's authorize endpoint, or an OmniAuth failure when misconfigured



140
141
142
143
144
145
146
147
148
149
# File 'lib/omniauth/strategies/authify.rb', line 140

def request_phase
  if missing_configuration?
    fail!(:missing_configuration, CallbackError.new(
                                    :missing_configuration,
                                    "The :site and :organization options are required"
                                  ))
  else
    super
  end
end