From ff2130c54a74999893ecd93981f7533d29c7cbbf Mon Sep 17 00:00:00 2001 From: "Justin Craig-Kuhn (JCK)" Date: Wed, 11 Dec 2024 02:20:44 -0800 Subject: [PATCH] Improve OAuth login --- app/controllers/oauth/sorcery_controller.rb | 46 ++++++++++++++++---- app/javascript/stylesheets/feedback.css.scss | 2 + app/models/concerns/sorcery_authenticable.rb | 6 +-- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/app/controllers/oauth/sorcery_controller.rb b/app/controllers/oauth/sorcery_controller.rb index 9a45ea883..aba9bf619 100644 --- a/app/controllers/oauth/sorcery_controller.rb +++ b/app/controllers/oauth/sorcery_controller.rb @@ -1,17 +1,26 @@ +require "typhoeus" + class Oauth::SorceryController < ApplicationController def login login_at(params[:provider]) end def callback - user = login_from(params[:provider], true) || create_from(params[:provider]) + provider = params[:provider] + auth = build_auth_hash(provider) + user = User.where(email: auth[:email]).first_or_initialize + user.save! unless user.persisted? + + user.authentications.where(provider:).first_or_create! do |authentication| + authentication.uid = auth[:uid] + end + + reset_session store_user_data_in_session(user) redirect_to root_path - rescue ActiveRecord::RecordNotUnique - redirect_to root_path, alert: "That email address has already been taken" rescue StandardError => e Sentry.capture_exception(e) - redirect_to root_path, alert: "Login via Google failed" + redirect_to root_path, alert: "Login with Google failed" end private @@ -23,10 +32,6 @@ def store_user_data_in_session(user) session[:email] = user.email end - def provider_title - params[:provider].titleize - end - def jwt_for(user) JWT.encode( { @@ -37,4 +42,29 @@ def jwt_for(user) "HS256" ) end + + def build_auth_hash(provider) + response = Typhoeus.get \ + "https://www.googleapis.com/oauth2/v2/userinfo", + headers: { Authorization: "Bearer #{fetch_access_token}" } + data = JSON.parse(response.body) + { + uid: data["id"], + email: data["email"] + } + end + + def fetch_access_token + response = Typhoeus.post( + "https://oauth2.googleapis.com/token", + body: { + code: params[:code], + client_id: Rails.application.config.sorcery.google.key, + client_secret: Rails.application.config.sorcery.google.secret, + redirect_uri: Rails.application.config.sorcery.google.callback_url, + grant_type: "authorization_code" + } + ) + JSON.parse(response.body)["access_token"] + end end diff --git a/app/javascript/stylesheets/feedback.css.scss b/app/javascript/stylesheets/feedback.css.scss index 640b1e671..20bb35793 100644 --- a/app/javascript/stylesheets/feedback.css.scss +++ b/app/javascript/stylesheets/feedback.css.scss @@ -18,6 +18,7 @@ font-size: 1.4rem; width: 20rem; animation: popOut 0.3s ease-in-out; + overflow: hidden; &.notice { background-color: $bg-blue; @@ -44,6 +45,7 @@ height: 4px; background-color: $header-gray; animation: progress 5s linear forwards; + // margin: 0 -1rem -1rem -1rem; } } diff --git a/app/models/concerns/sorcery_authenticable.rb b/app/models/concerns/sorcery_authenticable.rb index 90507d873..32c73e183 100644 --- a/app/models/concerns/sorcery_authenticable.rb +++ b/app/models/concerns/sorcery_authenticable.rb @@ -11,10 +11,10 @@ module SorceryAuthenticable presence: true, uniqueness: true, format: { - with: /\A[A-Za-z0-9_]{4,15}\z/, + with: /\A[A-Za-z0-9_]{3,15}\z/, message: "may contain only letters, numbers, and " \ "underscores, must be unique, and must be " \ - "4 to 15 characters long" + "3 to 15 characters long" } validates :email, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP } validates :password, length: { minimum: 5 }, if: :password @@ -30,7 +30,7 @@ def assign_username_from_email name = email.split("@").first.gsub(/[^A-Za-z0-9_]/, "_") name = "#{name.first(10)}_#{SecureRandom.hex(2)}" if User.where(username: name).exists? - self.username = name + self.username = name.first(15) end end end