# typed: ignore # frozen_string_literal: true module Setsuzoku module Service module WebService module AuthStrategies # The API OAuth Authentication Interface definition. # Any Plugin that implements this must implement all methods required for OAuth. # # Defines all necessary methods for handling authentication for any authentication strategy. module StrategyCanUseTokens extend T::Sig extend T::Helpers # # refresh_expired_token! sig { abstract.void } # # Construct the custom token_request_body and request a token. # # @return [void] def new_token!; end # # refresh_expired_token! sig { abstract.void } # # Construct the custom token_request_body and request a token. # # @return [void] def refresh_expired_token!; end # # auth_credential_valid? sig { returns(T::Boolean) } # # If the auth credentials are valid for this instance and auth_strategy. # # If the token is invalid we should refresh it. And verify that the credentials are now valid. # Otherwise the credentials are already valid. # # @return [Boolean] true if the auth token is valid for the auth_strategy. def auth_credential_valid? validate_token_credential! end private # # validate_token_credential! sig { returns(T::Boolean) } # # If the auth credentials are valid for this instance and auth_strategy. # # If the token is invalid we should refresh it. And verify that the credentials are now valid. # Otherwise the credentials are already valid. # # @return [Boolean] true if the auth token is valid for the auth_strategy. def validate_token_credential! if self.credential.status == 'disabled' false elsif uses_token? if token_is_invalid? self.refresh_expired_token! !token_is_invalid? else true end else true end end # # uses_token? sig { returns(T::Boolean) } # # If the plugin's auth_strategy should use a token. # # @return [Boolean] if the auth_strategy uses a token or not. def uses_token? uses_token_by_default? || !!self.credential&.uses_token? end # # uses_token_by_default? sig { returns(T::Boolean) } # # If the plugin's auth_strategy should use a token by default. # Defaulted to false, OAuth will default to true. # # @return [Boolean] if the auth_strategy uses a token or not. def uses_token_by_default? false end # # refresh_expired_token! sig { abstract.void } # # Exchange refresh_token for a new token and expires_on. # # @return [Boolean] true if the credential was refreshed successfully def refresh_expired_token!; end # # token_is_invalid? sig { returns(T::Boolean) } # # Determine whether the token is no longer valid. # # @return [Boolean] true if the token is invalid. def token_is_invalid? inactive = self.credential.status != 'active' expired = self.credential.expires_on.present? && self.credential.refresh_token.present? && (self.credential.expires_on < refresh_before_expiration_time) inactive || expired end sig { returns(DateTime) } def refresh_before_expiration_time 45.minutes.from_now.to_datetime end # # get_token! sig { params(body: T::Hash[Symbol, String], action: Symbol).void } # # Exchange code for a new token via POST request to API token url, # and set token, expiry, and status on the integration # # @param [Hash] body the request body for the token POST request # # @return void def get_token!(body, action) success = false without_headers = self.credential.auth_actions[action].has_key?(:without_headers) ? self.credential.auth_actions[action][:without_headers] : true request = self.api_strategy.request_class.new(action: action, body: body, without_headers: without_headers) resp = self.api_strategy.call_external_api(request: request, strategy: :auth) return false unless resp.success self.credential.set_token!(resp) end end end end end end