Skip to content

Instantly share code, notes, and snippets.

@fractaledmind
Last active September 12, 2023 11:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fractaledmind/762a76ba245196b4d506c666bea1e0f2 to your computer and use it in GitHub Desktop.
Save fractaledmind/762a76ba245196b4d506c666bea1e0f2 to your computer and use it in GitHub Desktop.
A standard Rails controller to take ownership of the OAuth process from the OmniAuth gem
class Sessions::OmniauthController < ApplicationController
skip_before_action :verify_authenticity_token
skip_before_action :authenticate!
# GET|POST /auth/:provider
def passthru
render status: 404, plain: "Not found. Authentication passthru."
end
# GET|POST /auth/:provider/callback
def create
# https://github.com/omniauth/omniauth/wiki/Saving-User-Location
origin_path = root_path
notice = "Signed in successfully via #{OmniAuth::Providers[auth.provider.to_sym]}"
if connected_account.present?
connected_account.update(connected_account_params)
ensure_tester_record_if_tester_role_for(connected_account.user)
sign_in_user(connected_account.user)
redirect_to origin_path, notice: notice
elsif Current.user.present?
connected_account = Current.user.connected_accounts.create(connected_account_params)
ensure_tester_record_if_tester_role_for(Current.user)
redirect_to origin_path, notice: notice
elsif (auth_user = User.find_by(email: auth.info.email.downcase)).present?
# since we control the Users table,
# allow the account to be connected to the existing user
# and then sign in the user
connected_account = auth_user.connected_accounts.create(connected_account_params)
ensure_tester_record_if_tester_role_for(auth_user)
sign_in_user(auth_user)
redirect_to origin_path, notice: notice
else
email = auth.info.email.downcase
username = auth.info.screen_name || email.split("@").first
user = User.new(
username: username,
email: email,
password: username.bytes.take(3).join
)
user.connected_accounts.new(connected_account_params)
if user.save
ensure_tester_record_if_tester_role_for(user)
sign_in_user(user)
redirect_to origin_path, notice: notice
else
redirect_to sign_in_path, alert: "Authentication failed"
end
end
end
def failure
redirect_to sign_in_path, alert: params[:message]
end
private
def ensure_tester_record_if_tester_role_for(user)
testio_uid = auth.info.roles.dig("tester", "id")
if (tester = Tester.find_by(testio_uid: testio_uid))
tester.update_column(:user_id, user.id) unless tester.user_id?
elsif auth.info.roles&.dig("tester").present?
Tester.insert(
{ email: auth.info.email.downcase,
phone_number: "+0000000000",
testio_uid: testio_uid,
first_name: auth.info.first_name,
last_name: auth.info.last_name,
birthdate: Date.new(rand(1970..2000), rand(1..12), rand(1..28)),
user_id: user.id,
},
unique_by: :email
)
end
end
def connected_account_params
# Clean auth hash credentials
auth_hash = auth.to_hash
auth_hash.delete("credentials")
auth_hash["extra"]&.delete("access_token")
expires_at = auth.credentials.expires_at.present? ?
Time.at(auth.credentials.expires_at) :
nil
{
provider: auth.provider,
uid: auth.uid,
email: auth.info.email.downcase,
access_token: auth.credentials.token,
access_token_secret: auth.credentials.secret,
expires_at: expires_at,
refresh_token: auth.credentials.refresh_token,
auth: auth_hash
}
end
def connected_account
@connected_account ||= User::ConnectedAccount.for_auth(auth)
end
def auth
@auth ||= request.env["omniauth.auth"]
end
end
OmniAuth::Providers = {}
Rails.application.config.middleware.use OmniAuth::Builder do
unless Rails.env.production?
provider :developer
OmniAuth::Providers[:developer] = "Developer"
end
provider OmniAuth::Strategies::TestIO,
Rails.application.credentials.omniauth.testio.public_key, # app_id
Rails.application.credentials.omniauth.testio.private_key, # app_secret
scope: if Rails.env.production?
"public"
else
"public user_api:admin custom_task_api:admin"
end
OmniAuth::Providers[:testio] = "Test IO"
end
# OmniAuth routes
get '/auth/failure',
to: 'sessions/omniauth#failure'
match 'auth/:provider',
to: 'sessions/omniauth#passthru',
as: 'omniauth_authorize',
via: [:get, :post]
match 'auth/:provider/callback',
to: 'sessions/omniauth#create',
as: 'omniauth_callback',
via: [:get, :post]
<div class="text-center mt-12">
<h1 class="text-4xl font-bold leading-7 sm:text-5xl">
Log in
</h1>
<p class="text-gray-800 text-lg mt-4 mb-12">
You'll be taken to a 3rd party provider to authenticate.
</p>
<div class="flex flex-col items-center gap-3">
<% ::OmniAuth::Providers.each do |provider, label| %>
<%= button_to omniauth_authorize_path(provider: provider, origin: session['origin']), data: { turbo: false }, class: button_classes(type: :primary) do %>
<span>Sign in with <%= label %></span>
<% end %>
<% end %>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment