Skip to content

Commit bf5b34d

Browse files
authored
Merge pull request #70 from brunoluigi/bruno/google-oauth
Google OAuth
2 parents 72918bf + 356577b commit bf5b34d

File tree

14 files changed

+137
-11
lines changed

14 files changed

+137
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@
3535

3636
/app/assets/builds/*
3737
!/app/assets/builds/.keep
38+
.DS_Store

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ gem "tailwind_merge", "~> 1.3.1"
2525
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
2626
gem "bcrypt", "~> 3.1.20"
2727

28+
gem "omniauth", "~> 2.1"
29+
gem "omniauth-google-oauth2", "~> 1.1"
30+
2831
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
2932
gem "tzinfo-data", platforms: %i[ windows jruby ]
3033

Gemfile.lock

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,18 @@ GEM
110110
erubi (1.13.1)
111111
et-orbi (1.2.11)
112112
tzinfo
113+
faraday (2.13.1)
114+
faraday-net_http (>= 2.0, < 3.5)
115+
json
116+
logger
117+
faraday-net_http (3.4.0)
118+
net-http (>= 0.5.0)
113119
fugit (1.11.1)
114120
et-orbi (~> 1, >= 1.2.11)
115121
raabro (~> 1.4)
116122
globalid (1.2.1)
117123
activesupport (>= 6.1)
124+
hashie (5.0.0)
118125
i18n (1.14.7)
119126
concurrent-ruby (~> 1.0)
120127
importmap-rails (2.1.0)
@@ -130,6 +137,8 @@ GEM
130137
actionview (>= 5.0.0)
131138
activesupport (>= 5.0.0)
132139
json (2.12.0)
140+
jwt (2.10.1)
141+
base64
133142
kamal (2.8.1)
134143
activesupport (>= 7.0)
135144
base64 (~> 0.2)
@@ -157,6 +166,10 @@ GEM
157166
mini_mime (1.1.5)
158167
minitest (5.25.5)
159168
msgpack (1.8.0)
169+
multi_xml (0.7.2)
170+
bigdecimal (~> 3.1)
171+
net-http (0.6.0)
172+
uri
160173
net-imap (0.5.8)
161174
date
162175
net-protocol
@@ -186,6 +199,26 @@ GEM
186199
racc (~> 1.4)
187200
nokogiri (1.18.8-x86_64-linux-musl)
188201
racc (~> 1.4)
202+
oauth2 (2.0.10)
203+
faraday (>= 0.17.3, < 4.0)
204+
jwt (>= 1.0, < 4.0)
205+
logger (~> 1.2)
206+
multi_xml (~> 0.5)
207+
rack (>= 1.2, < 4)
208+
snaky_hash (~> 2.0)
209+
version_gem (>= 1.1.8, < 3)
210+
omniauth (2.1.3)
211+
hashie (>= 3.4.6)
212+
rack (>= 2.2.3)
213+
rack-protection
214+
omniauth-google-oauth2 (1.2.1)
215+
jwt (>= 2.9.2)
216+
oauth2 (~> 2.0)
217+
omniauth (~> 2.0)
218+
omniauth-oauth2 (~> 1.8)
219+
omniauth-oauth2 (1.8.0)
220+
oauth2 (>= 1.4, < 3)
221+
omniauth (~> 2.0)
189222
ostruct (0.6.1)
190223
parallel (1.27.0)
191224
parser (3.3.8.0)
@@ -217,6 +250,10 @@ GEM
217250
raabro (1.4.0)
218251
racc (1.8.1)
219252
rack (3.1.15)
253+
rack-protection (4.1.1)
254+
base64 (>= 0.1.0)
255+
logger (>= 1.6.0)
256+
rack (>= 3.0.0, < 4)
220257
rack-session (2.1.1)
221258
base64 (>= 0.1.0)
222259
rack (>= 3.0.0)
@@ -302,7 +339,7 @@ GEM
302339
rbs (>= 3, < 5)
303340
ruby-lsp-rails (0.4.8)
304341
ruby-lsp (>= 0.26.0, < 0.27.0)
305-
ruby-lsp-rspec (0.1.27)
342+
ruby-lsp-rspec (0.1.28)
306343
ruby-lsp (~> 0.26.0)
307344
ruby-progressbar (1.13.0)
308345
ruby_ui (1.0.1)
@@ -315,6 +352,9 @@ GEM
315352
rubyzip (>= 1.2.2, < 4.0)
316353
websocket (~> 1.0)
317354
sin_lru_redux (2.5.2)
355+
snaky_hash (2.0.1)
356+
hashie
357+
version_gem (~> 1.1, >= 1.1.1)
318358
solid_cable (3.0.8)
319359
actioncable (>= 7.2)
320360
activejob (>= 7.2)
@@ -370,6 +410,7 @@ GEM
370410
unicode-emoji (4.0.4)
371411
uri (1.0.3)
372412
useragent (0.16.11)
413+
version_gem (1.1.8)
373414
web-console (4.2.1)
374415
actionview (>= 6.0.0)
375416
activemodel (>= 6.0.0)
@@ -404,6 +445,8 @@ DEPENDENCIES
404445
importmap-rails (~> 2.1.0)
405446
jbuilder (~> 2.13.0)
406447
kamal (~> 2.8.1)
448+
omniauth (~> 2.1)
449+
omniauth-google-oauth2 (~> 1.1)
407450
pg (~> 1.5.9)
408451
phlex-rails (~> 2.3.1)
409452
propshaft (~> 1.1.0)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class OmniauthCallbacksController < ApplicationController
2+
allow_unauthenticated_access only: [ :google_oauth2 ]
3+
4+
def google_oauth2
5+
auth = request.env["omniauth.auth"]
6+
user = User.find_or_create_from_omniauth(auth)
7+
if user.persisted?
8+
start_new_session_for(user)
9+
redirect_to after_authentication_url, notice: "Signed in with Google!"
10+
else
11+
redirect_to new_session_path, alert: "Could not authenticate via Google."
12+
end
13+
end
14+
15+
def failure
16+
redirect_to new_session_path, alert: "Google authentication failed."
17+
end
18+
end

app/controllers/sessions_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class SessionsController < ApplicationController
2-
allow_unauthenticated_access only: %i[ new create ]
2+
allow_unauthenticated_access only: %i[ new create ] # (Google OAuth handled in OmniauthCallbacksController)
33
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." }
44

55
def new

app/models/user.rb

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,28 @@ class User < ApplicationRecord
99

1010
validates :name, presence: true
1111
validates :email_address, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
12-
validates :phone, format: { with: /\A\d+\z/, message: "must contain only digits" }
12+
validates :phone, format: { with: /\A\d+\z/, message: "must contain only digits" }, allow_blank: true
1313
validates :password, length: { minimum: 8 }, if: -> { password.present? }
14+
15+
def self.find_or_create_from_omniauth(auth)
16+
user = find_by(provider: auth.provider, uid: auth.uid)
17+
if user
18+
user
19+
else
20+
email = auth.info.email
21+
user = find_by(email_address: email)
22+
if user
23+
user.update(provider: auth.provider, uid: auth.uid)
24+
user
25+
else
26+
create(
27+
provider: auth.provider,
28+
uid: auth.uid,
29+
name: auth.info.name || email,
30+
email_address: email,
31+
password: SecureRandom.hex(16)
32+
)
33+
end
34+
end
35+
end
1436
end

app/views/sessions/new.html.erb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@
3737
<div class="found-it-form-actions">
3838
<%= form.submit "Sign in", class: "found-it-button" %>
3939
</div>
40+
41+
<div class="found-it-divider">
42+
<span>or</span>
43+
</div>
44+
45+
<div class="found-it-form-actions">
46+
<%= link_to "Sign in with Google", "/auth/google_oauth2", class: "found-it-button found-it-google-btn", method: :post %>
47+
</div>
4048

4149
<div class="found-it-links">
4250
<%= link_to "Forgot password?", new_password_path, class: "found-it-link" %>

config/credentials.yml.enc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
zkJDCWKx0S9W8W8G5syXjnY718m+2HPwHMFXPIDEwuvQ9HvXMSIWfyZDzfMxNiGApjbhfURPHW2kSQzKeiGMwQLiYXOfkgaAea5u+t4fT0UQquEpZWTJhB9z89G7gQVxmgeb12e9f3krATP04gBgQH6yBa9w8a0x4tYZEUFEfcdSCoSlyqdVNO2YLB2qDOQ+rTPc0yyA6sWkHTM6RiHl/a/c9tGCDe4C/4PWe6oslau1VnX0g36G0pEvqPsIbW5P4DoJI5tTCWUJrq4KGO2+zyCZlzq8Raw88JVPfLGtbHmkR5zLZmY5m4ZlG6YD+AFkI7RY+UERmw9jlM23y/DM027l2LaQUrIthi5HqeG4Kgw+nJ4X1C8f61NmJ0b3zF/1Tn4VcWdTnQfO6P+Vkik939wmvPa8ZuuL4AVUuNfvm1P/aSzd+gidxcA+IkPe0hb/XuE2PEilJZPvBoNw1+TB/QMp9aCtgPEf4jyoaAyuDnNCD4O5WAEOgilT--YhpIBc6U10frzyzV--YExmVS4SOmYzTciqcirv3A==
1+
TaIkiJyOnI7tbFPn2ly4R93NsZ9fH+s6Z9k10kp2roP1HSkzT8SKAR+Ubb89Y3XrhRXQUrE//nSEDSrW7ftu/1q5HCJyQyY3MPtev/YvV2cyRtC6Lfd7V5MiFzkphS/uFi6ee6b3H9m+h2pUl97S1p4iTbyEOZKsYZ99gcyTMzSKj3vq2IVoUlgZReQeIgXkCCb2+k5yAzts2VwcIpWJdChFKjffu/1sW0yucBetW0gFMMKZGgawxXb5jNVNbNZ07JtHrzcx+uq5gVmMMCtK2PxRvbaDdDka6ERG0IT3TEBTHp94bhz7xShdLxGfgNuIiltGknTgJxFt7dnq+IpfNmawLRdThj2rG7nVISflJSqnUTSLGMLFqkdI6SBmrg9S8J9WnDk+C4F+nxhNqYEJaswAtYP40bWKPLuU6qBBPgF7CX0u6VG7mJjmMszcx6Zmz6SrQazEpF6sjXEYFDlws6/BZgF1gEtgg2fhijFPM78lkeW2F1q+5DKOidS0TvF1BX9EPHTDMjlVOd6oj6/xJg2BbIKzCo/eBbR0xMQmh4+WOT1VEfsC27thrWca6fL2nLuzNarW8drQG80R5wkYUC4pJFpVFhGWwBgJGhdP0g2wxB1X2nTPnIhTbW7uSXjRTgyP0ArAl/MmQX0SMarfdXnHRM6nuulx+YA6aLOC5BR/PsG3OcSvPyn31ky1sc3TSATvJA==--LcWYjGffxups9iCj--oC0o+OVsqgFCUWTHBgWgxg==

config/initializers/omniauth.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Rails.application.config.middleware.use OmniAuth::Builder do
2+
provider :google_oauth2,
3+
Rails.application.credentials.dig(:google_oauth, :client_id),
4+
Rails.application.credentials.dig(:google_oauth, :client_secret),
5+
{
6+
scope: "email,profile",
7+
prompt: "select_account",
8+
access_type: "offline"
9+
}
10+
end
11+
12+
OmniAuth.config.allowed_request_methods = %i[get]
13+
OmniAuth.config.silence_get_warning = true

config/routes.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
Rails.application.routes.draw do
2+
get "/auth/:provider/callback", to: "omniauth_callbacks#google_oauth2"
3+
get "/auth/failure", to: "omniauth_callbacks#failure"
24
get "items/index"
35
# Public item info endpoint by UUID
46
resources :item_views, only: [ :show, :update ] do

0 commit comments

Comments
 (0)