diff --git a/.gitignore b/.gitignore index df897d3d..d6b169bf 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,6 @@ spec/rails_app/log/* Gemfile*.lock gemfiles/*.lock .ruby-version -tags \ No newline at end of file +tags + +vendor/bundle \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 08891148..23b03dda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog ## HEAD +* Add support for Google One Tap sign-in +[#336](https://github.com/Sorcery/sorcery/pull/336) + ## 0.16.5 * Raise ArgumentError when calling change_password! with blank password [#333](https://github.com/Sorcery/sorcery/pull/333) diff --git a/lib/sorcery/controller/submodules/external.rb b/lib/sorcery/controller/submodules/external.rb index 019a67a4..09e9782e 100644 --- a/lib/sorcery/controller/submodules/external.rb +++ b/lib/sorcery/controller/submodules/external.rb @@ -79,23 +79,47 @@ def sorcery_login_url(provider_name, args = {}) # get the user hash from a provider using information from the params and session. def sorcery_fetch_user_hash(provider_name) - # the application should never ask for user hashes from two different providers - # on the same request. But if they do, we should be ready: on the second request, - # clear out the instance variables if the provider is different - provider = sorcery_get_provider provider_name - if @provider.nil? || @provider != provider - @provider = provider - @access_token = nil - @user_hash = nil - end + sorcery_init_user_hash(provider_name) - # delegate to the provider for the access token and the user hash. - # cache them in instance variables. - @access_token ||= @provider.process_callback(params, session) # sends request to oauth agent to get the token - @user_hash ||= @provider.get_user_hash(@access_token) # uses the token to send another request to the oauth agent requesting user info + if provider_name == 'google' && params[:credential].present? + sorcery_get_google_user_hash + else + sorcery_fetch_provider_user_hash + end nil end + # the application should never ask for user hashes from two different providers + # on the same request. But if they do, we should be ready: on the second request, + # clear out the instance variables if the provider is different + def sorcery_init_user_hash(provider_name) + provider = sorcery_get_provider provider_name + return unless @provider.nil? || @provider != provider + + @provider = provider + @access_token = nil + @user_hash = nil + end + + def sorcery_get_google_user_hash + @user_hash = {} + @user_hash[:user_info] = + Google::Auth::IDTokens.verify_oidc(params['credential'], + aud: Rails.application.config.sorcery.google.key) + @user_hash[:uid] = @user_hash[:user_info]['sub'] + end + + # delegate to the provider for the access token and the user hash. + # cache them in instance variables. + # rubocop: disable Naming/MemoizedInstanceVariableName + def sorcery_fetch_provider_user_hash + # sends request to oauth agent to get the token + @access_token ||= @provider.process_callback(params, session) + # uses the token to send another request to the oauth agent requesting user info + @user_hash ||= @provider.get_user_hash(@access_token) + end + # rubocop: enable Naming/MemoizedInstanceVariableName + # for backwards compatibility def access_token(*_args) @access_token diff --git a/sorcery.gemspec b/sorcery.gemspec index 44e76074..34c03acb 100644 --- a/sorcery.gemspec +++ b/sorcery.gemspec @@ -36,6 +36,7 @@ Gem::Specification.new do |s| s.add_dependency 'bcrypt', '~> 3.1' s.add_dependency 'oauth', '>= 0.6' s.add_dependency 'oauth2', '~> 2.0' + s.add_dependency 'googleauth', '~> 1.3' s.add_development_dependency 'byebug', '~> 10.0.0' s.add_development_dependency 'rspec-rails', '~> 3.7.0'