refactor: use state-based authentication (#11690)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -1,32 +1,23 @@
|
||||
class Api::V1::Accounts::Google::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||
class Api::V1::Accounts::Google::AuthorizationsController < Api::V1::Accounts::OauthAuthorizationController
|
||||
include GoogleConcern
|
||||
before_action :check_authorization
|
||||
|
||||
def create
|
||||
email = params[:authorization][:email]
|
||||
redirect_url = google_client.auth_code.authorize_url(
|
||||
{
|
||||
redirect_uri: "#{base_url}/google/callback",
|
||||
scope: 'email profile https://mail.google.com/',
|
||||
scope: scope,
|
||||
response_type: 'code',
|
||||
prompt: 'consent', # the oauth flow does not return a refresh token, this is supposed to fix it
|
||||
access_type: 'offline', # the default is 'online'
|
||||
state: state,
|
||||
client_id: GlobalConfigService.load('GOOGLE_OAUTH_CLIENT_ID', nil)
|
||||
}
|
||||
)
|
||||
|
||||
if redirect_url
|
||||
cache_key = "google::#{email.downcase}"
|
||||
::Redis::Alfred.setex(cache_key, Current.account.id, 5.minutes)
|
||||
render json: { success: true, url: redirect_url }
|
||||
else
|
||||
render json: { success: false }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_authorization
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
class Api::V1::Accounts::Instagram::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||
class Api::V1::Accounts::Instagram::AuthorizationsController < Api::V1::Accounts::OauthAuthorizationController
|
||||
include InstagramConcern
|
||||
include Instagram::IntegrationHelper
|
||||
before_action :check_authorization
|
||||
|
||||
def create
|
||||
# https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/business-login#step-1--get-authorization
|
||||
@@ -21,10 +20,4 @@ class Api::V1::Accounts::Instagram::AuthorizationsController < Api::V1::Accounts
|
||||
render json: { success: false }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_authorization
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
class Api::V1::Accounts::Microsoft::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||
class Api::V1::Accounts::Microsoft::AuthorizationsController < Api::V1::Accounts::OauthAuthorizationController
|
||||
include MicrosoftConcern
|
||||
before_action :check_authorization
|
||||
|
||||
def create
|
||||
email = params[:authorization][:email]
|
||||
redirect_url = microsoft_client.auth_code.authorize_url(
|
||||
{
|
||||
redirect_uri: "#{base_url}/microsoft/callback",
|
||||
scope: 'offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid profile',
|
||||
scope: scope,
|
||||
state: state,
|
||||
prompt: 'consent'
|
||||
}
|
||||
)
|
||||
if redirect_url
|
||||
cache_key = "microsoft::#{email.downcase}"
|
||||
::Redis::Alfred.setex(cache_key, Current.account.id, 5.minutes)
|
||||
render json: { success: true, url: redirect_url }
|
||||
else
|
||||
render json: { success: false }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_authorization
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
class Api::V1::Accounts::OauthAuthorizationController < Api::V1::Accounts::BaseController
|
||||
before_action :check_authorization
|
||||
|
||||
protected
|
||||
|
||||
def scope
|
||||
''
|
||||
end
|
||||
|
||||
def state
|
||||
Current.account.to_sgid(expires_in: 15.minutes).to_s
|
||||
end
|
||||
|
||||
def base_url
|
||||
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_authorization
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
end
|
||||
@@ -14,7 +14,7 @@ module GoogleConcern
|
||||
|
||||
private
|
||||
|
||||
def base_url
|
||||
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
|
||||
def scope
|
||||
'email profile https://mail.google.com/'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ module MicrosoftConcern
|
||||
|
||||
private
|
||||
|
||||
def base_url
|
||||
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
|
||||
def scope
|
||||
'offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid profile email'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,6 @@ class OauthCallbackController < ApplicationController
|
||||
)
|
||||
|
||||
handle_response
|
||||
::Redis::Alfred.delete(cache_key)
|
||||
rescue StandardError => e
|
||||
ChatwootExceptionTracker.new(e).capture_exception
|
||||
redirect_to '/'
|
||||
@@ -64,10 +63,6 @@ class OauthCallbackController < ApplicationController
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def cache_key
|
||||
"#{provider_name}::#{users_data['email'].downcase}"
|
||||
end
|
||||
|
||||
def create_channel_with_inbox
|
||||
ActiveRecord::Base.transaction do
|
||||
channel_email = Channel::Email.create!(email: users_data['email'], account: account)
|
||||
@@ -86,12 +81,17 @@ class OauthCallbackController < ApplicationController
|
||||
decoded_token[0]
|
||||
end
|
||||
|
||||
def account_id
|
||||
::Redis::Alfred.get(cache_key)
|
||||
def account_from_signed_id
|
||||
raise ActionController::BadRequest, 'Missing state variable' if params[:state].blank?
|
||||
|
||||
account = GlobalID::Locator.locate_signed(params[:state])
|
||||
raise 'Invalid or expired state' if account.nil?
|
||||
|
||||
account
|
||||
end
|
||||
|
||||
def account
|
||||
@account ||= Account.find(account_id)
|
||||
@account ||= account_from_signed_id
|
||||
end
|
||||
|
||||
# Fallback name, for when name field is missing from users_data
|
||||
|
||||
@@ -12,7 +12,6 @@ defineOptions({
|
||||
provider="google"
|
||||
:title="$t('INBOX_MGMT.ADD.GOOGLE.TITLE')"
|
||||
:description="$t('INBOX_MGMT.ADD.GOOGLE.DESCRIPTION')"
|
||||
:input-placeholder="$t('INBOX_MGMT.ADD.GOOGLE.EMAIL_PLACEHOLDER')"
|
||||
:submit-button-text="$t('INBOX_MGMT.ADD.GOOGLE.SIGN_IN')"
|
||||
:error-message="$t('INBOX_MGMT.ADD.GOOGLE.ERROR_MESSAGE')"
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,6 @@ defineOptions({
|
||||
provider="microsoft"
|
||||
:title="$t('INBOX_MGMT.ADD.MICROSOFT.TITLE')"
|
||||
:description="$t('INBOX_MGMT.ADD.MICROSOFT.DESCRIPTION')"
|
||||
:input-placeholder="$t('INBOX_MGMT.ADD.MICROSOFT.EMAIL_PLACEHOLDER')"
|
||||
:submit-button-text="$t('INBOX_MGMT.ADD.MICROSOFT.SIGN_IN')"
|
||||
:error-message="$t('INBOX_MGMT.ADD.MICROSOFT.ERROR_MESSAGE')"
|
||||
/>
|
||||
|
||||
@@ -30,14 +30,9 @@ const props = defineProps({
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
inputPlaceholder: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const isRequestingAuthorization = ref(false);
|
||||
const email = ref('');
|
||||
|
||||
const client = computed(() => {
|
||||
if (props.provider === 'microsoft') {
|
||||
@@ -50,9 +45,7 @@ const client = computed(() => {
|
||||
async function requestAuthorization() {
|
||||
try {
|
||||
isRequestingAuthorization.value = true;
|
||||
const response = await client.value.generateAuthorization({
|
||||
email: email.value,
|
||||
});
|
||||
const response = await client.value.generateAuthorization();
|
||||
const {
|
||||
data: { url },
|
||||
} = response;
|
||||
@@ -75,11 +68,6 @@ async function requestAuthorization() {
|
||||
:header-content="description"
|
||||
/>
|
||||
<form class="mt-6" @submit.prevent="requestAuthorization">
|
||||
<woot-input
|
||||
v-model="email"
|
||||
type="email"
|
||||
:placeholder="inputPlaceholder"
|
||||
/>
|
||||
<NextButton
|
||||
:is-loading="isRequestingAuthorization"
|
||||
type="submit"
|
||||
|
||||
Reference in New Issue
Block a user