engines/dfc_provider/app/services/dfc_request.rb
# frozen_string_literal: true
require "private_address_check"
require "private_address_check/tcpsocket_ext"
# Request a JSON document from a DFC API with authentication.
#
# All DFC API interactions are authenticated via OIDC tokens. If the user's
# access token is expired, we try to get a new one with the user's refresh
# token.
class DfcRequest
def initialize(user)
@user = user
end
def call(url, data = nil)
response = request(url, data)
if response.status >= 400 && token_stale?
refresh_access_token!
response = request(url, data)
end
response.body
end
private
def request(url, data = nil)
only_public_connections do
if data
connection.post(url, data)
else
connection.get(url)
end
end
end
def token_stale?
@user.oidc_account.updated_at < 15.minutes.ago
end
def connection
Faraday.new(
request: { timeout: 30 },
headers: {
'Content-Type' => 'application/json',
'Authorization' => "Bearer #{@user.oidc_account.token}",
}
)
end
def only_public_connections(&)
return yield if Rails.env.development?
PrivateAddressCheck.only_public_connections(&)
end
def refresh_access_token!
strategy = OmniAuth::Strategies::OpenIDConnect.new(
Rails.application,
Devise.omniauth_configs[:openid_connect].options
# Don't try to call `Devise.omniauth(:openid_connect)` first.
# It results in an empty config hash and we lose our config.
)
client = strategy.client
client.token_endpoint = strategy.config.token_endpoint
client.refresh_token = @user.oidc_account.refresh_token
token = client.access_token!
@user.oidc_account.update!(
token: token.access_token,
refresh_token: token.refresh_token
)
end
end