google_sign_in 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +40 -0
- data/MIT-LICENSE +20 -0
- data/README.md +73 -0
- data/Rakefile +10 -0
- data/google_sign_in.gemspec +19 -0
- data/lib/google_sign_in.rb +2 -0
- data/lib/google_sign_in/helper.rb +60 -0
- data/lib/google_sign_in/identity.rb +63 -0
- data/lib/google_sign_in/railtie.rb +12 -0
- data/test/identity_test.rb +9 -0
- data/test/test_helper.rb +4 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce2cbe6f38376f6f4ec06a59c7b0fcb916ed1611
|
4
|
+
data.tar.gz: 4acaea345f5840be79e9a2d77b301e96e2eaaf90
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: db6f84a43691f47461ad4d7572d165fd23b2010fbc1f28b96dd81c624eef1e1af3b5070b56d1dce1fcb8293ce85d8dd74e3b134ca75aa14d24b6be94216d633d
|
7
|
+
data.tar.gz: 7c3a4756ceaf4e6a7a96fee9ddf361843b6c46f61c825023ab2319290d46f0cdcb799fa24eea4d88f0e7bc34eaa62a3074badd56b51035a13f311a59a319b514
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
google_sign_in (0.1)
|
5
|
+
activesupport (>= 5.1)
|
6
|
+
google-id-token (>= 1.3.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activesupport (5.1.1)
|
12
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
|
+
i18n (~> 0.7)
|
14
|
+
minitest (~> 5.1)
|
15
|
+
tzinfo (~> 1.1)
|
16
|
+
byebug (9.0.6)
|
17
|
+
concurrent-ruby (1.0.5)
|
18
|
+
google-id-token (1.3.1)
|
19
|
+
jwt
|
20
|
+
multi_json
|
21
|
+
i18n (0.8.1)
|
22
|
+
jwt (1.5.6)
|
23
|
+
minitest (5.10.2)
|
24
|
+
multi_json (1.12.1)
|
25
|
+
rake (12.0.0)
|
26
|
+
thread_safe (0.3.6)
|
27
|
+
tzinfo (1.2.3)
|
28
|
+
thread_safe (~> 0.1)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
bundler (~> 1.15)
|
35
|
+
byebug
|
36
|
+
google_sign_in!
|
37
|
+
rake
|
38
|
+
|
39
|
+
BUNDLED WITH
|
40
|
+
1.15.0
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2017 David Heinemeier Hansson, Basecamp
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# Google Sign-In for Rails
|
2
|
+
|
3
|
+
Google Sign-In provides an easy and secure way to let users signin into and up for your service,
|
4
|
+
without adding yet-another per-app email/password combination. Integrating it into your Rails app
|
5
|
+
should be drop-in easy. This gem makes it so.
|
6
|
+
|
7
|
+
The only configuration needed is setting the Google client id for your application. [Google has a
|
8
|
+
tutorial on how to setup a client id](https://developers.google.com/identity/sign-in/web/server-side-flow#step_1_create_a_client_id_and_client_secret).
|
9
|
+
|
10
|
+
Once you have your client id, create a `config/initializers/google_sign_in_client_id.rb` file with this:
|
11
|
+
`GoogleSignIn::Identity.client_id = <THAT CLIENT ID YOU GOT FROM GOOGLE>`
|
12
|
+
|
13
|
+
Now you can use the sign-in integration on your signup or sigin screen.
|
14
|
+
|
15
|
+
## Example
|
16
|
+
|
17
|
+
Here's the most basic example:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# app/views/sessions/new.html.erb
|
21
|
+
<%= google_sign_in(url: session_path) do %>
|
22
|
+
<%= button_tag("Signin with Google") %>
|
23
|
+
<% end %>
|
24
|
+
```
|
25
|
+
|
26
|
+
The `url` option is the URL that the hidden form will be submitted against along with the Google ID Token
|
27
|
+
that's set after the user has picked the account and authenticated in the pop-up window Google provides.
|
28
|
+
|
29
|
+
You can then use that in a sessions controller like so:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class SessionsController < ApplicationController
|
33
|
+
def new
|
34
|
+
end
|
35
|
+
|
36
|
+
def create
|
37
|
+
if user = authenticate_via_google
|
38
|
+
cookies.signed[:user_id] = user.id
|
39
|
+
redirect_to user
|
40
|
+
else
|
41
|
+
redirect_to new_session_url, alert: "authentication_failed"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def authenticate_via_google
|
47
|
+
if params[:google_id_token].present?
|
48
|
+
User.find_by google_id: GoogleSignIn::Identity.new(params[:google_id_token]).user_id
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
(This example assumes that a user has already signed up for your service using Google Sign-In and that
|
55
|
+
you're storing the Google user id in the `User#google_id` attribute).
|
56
|
+
|
57
|
+
That's it! You can checkout the `GoogleSignIn::Identity` class for the thin wrapping it provides around
|
58
|
+
the decoding of the Google ID Token using the google-id-token library. Interrogating this identity object
|
59
|
+
for profile details is particularly helpful when you use Google for signup, as you can get the name, email
|
60
|
+
address, avatar url, and locale through it.
|
61
|
+
|
62
|
+
## Unreleased gem caveat
|
63
|
+
|
64
|
+
The gem google-id-token is currently behind its GitHub repository on the release schedule. The latest release
|
65
|
+
is version 1.3.1 from 2015. So for now, you should depend on the github version in your app's Gemfile:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
gem 'google-id-token', github: 'google/google-id-token'
|
69
|
+
```
|
70
|
+
|
71
|
+
## License
|
72
|
+
|
73
|
+
Google Sign-In for Rails is released under the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'google_sign_in'
|
3
|
+
s.version = '0.1'
|
4
|
+
s.authors = 'David Heinemeier Hansson'
|
5
|
+
s.email = 'david@basecamp.com'
|
6
|
+
s.summary = 'Sign in (or up) with Google for Rails applications'
|
7
|
+
s.homepage = 'https://github.com/basecamp/google_sign_in'
|
8
|
+
s.license = 'MIT'
|
9
|
+
|
10
|
+
s.required_ruby_version = '>= 1.9.3'
|
11
|
+
|
12
|
+
s.add_dependency 'activesupport', '>= 5.1'
|
13
|
+
s.add_dependency 'google-id-token', '>= 1.3.1'
|
14
|
+
|
15
|
+
s.add_development_dependency 'bundler', '~> 1.15'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'google_sign_in/identity'
|
2
|
+
|
3
|
+
module GoogleSignIn
|
4
|
+
module Helper
|
5
|
+
def google_sign_in(url:, &block)
|
6
|
+
content_for :head,
|
7
|
+
google_sign_in_javacript_include_tag +
|
8
|
+
google_sign_in_client_id_meta_tag
|
9
|
+
|
10
|
+
google_sign_in_javascript_tag +
|
11
|
+
google_sign_in_hidden_form_tag(url: url) +
|
12
|
+
google_sign_in_click_handler(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def google_sign_in_javacript_include_tag
|
17
|
+
javascript_include_tag "https://apis.google.com/js/platform.js?onload=setupGoogleSignIn", async: true, defer: true
|
18
|
+
end
|
19
|
+
|
20
|
+
def google_sign_in_client_id_meta_tag
|
21
|
+
tag.meta name: "google-signin-client_id", content: GoogleSignIn::Identity.client_id
|
22
|
+
end
|
23
|
+
|
24
|
+
def google_sign_in_hidden_form_tag(url:)
|
25
|
+
form_with url: url, id: "google_signin", html: { style: "display: none" } do |form|
|
26
|
+
form.hidden_field :google_id_token, id: "google_id_token"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def google_sign_in_click_handler(&block)
|
31
|
+
tag.div(onclick: 'selectGoogleSignInAccount(event)') { capture(&block) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def google_sign_in_javascript_tag
|
35
|
+
javascript_tag(<<-EOS
|
36
|
+
function setupGoogleSignIn() {
|
37
|
+
gapi.load("auth2", function () { gapi.auth2.init() })
|
38
|
+
}
|
39
|
+
|
40
|
+
function selectGoogleSignInAccount(event) {
|
41
|
+
event.preventDefault()
|
42
|
+
|
43
|
+
options = new gapi.auth2.SigninOptionsBuilder
|
44
|
+
options.setPrompt("select_account")
|
45
|
+
|
46
|
+
gapi.auth2.getAuthInstance().signIn(options).then(function (googleUser) {
|
47
|
+
var token = googleUser.getAuthResponse().id_token
|
48
|
+
|
49
|
+
if (token !== null) {
|
50
|
+
document.getElementById('google_id_token').value = token
|
51
|
+
document.getElementById('google_signin').submit()
|
52
|
+
gapi.auth2.getAuthInstance().signOut()
|
53
|
+
}
|
54
|
+
})
|
55
|
+
}
|
56
|
+
EOS
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'google-id-token'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
require 'active_support/core_ext/numeric/time'
|
4
|
+
|
5
|
+
module GoogleSignIn
|
6
|
+
class Identity
|
7
|
+
class_attribute :client_id
|
8
|
+
|
9
|
+
class_attribute :token_expiry
|
10
|
+
self.token_expiry = 5.minutes
|
11
|
+
|
12
|
+
class_attribute :logger
|
13
|
+
self.logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
14
|
+
|
15
|
+
def initialize(token)
|
16
|
+
ensure_client_id_present
|
17
|
+
set_extracted_payload(token)
|
18
|
+
ensure_proper_audience
|
19
|
+
end
|
20
|
+
|
21
|
+
def user_id
|
22
|
+
@payload["sub"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def name
|
26
|
+
@payload["name"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def email_address
|
30
|
+
@payload["email"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def email_verified?
|
34
|
+
@payload["email_verified"] == "true"
|
35
|
+
end
|
36
|
+
|
37
|
+
def avatar_url
|
38
|
+
@payload["picture"]
|
39
|
+
end
|
40
|
+
|
41
|
+
def locale
|
42
|
+
@payload["locale"]
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def ensure_client_id_present
|
47
|
+
if client_id.blank?
|
48
|
+
raise ArgumentError, "GoogleSignIn.client_id must be set to validate identity"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_extracted_payload(token)
|
53
|
+
@payload = GoogleIDToken::Validator.new(expiry: token_expiry).check(token, client_id)
|
54
|
+
rescue GoogleIDToken::ValidationError => e
|
55
|
+
logger.error "Google token failed to validate (#{e.message})"
|
56
|
+
@payload = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def ensure_proper_audience
|
60
|
+
@payload["aud"].include?(client_id)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
require 'google_sign_in/helper'
|
3
|
+
|
4
|
+
module GoogleSignIn
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
initializer :google_sign_in do |app|
|
7
|
+
ActiveSupport.on_load :action_controller do
|
8
|
+
ActionController::Base.send :helper, GoogleSignIn::Helper
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'google_sign_in/identity'
|
3
|
+
|
4
|
+
class GoogleSignIn::IdentityTest < ActiveSupport::TestCase
|
5
|
+
test "client_id must be set" do
|
6
|
+
GoogleSignIn::Identity.client_id = nil
|
7
|
+
assert_raises(ArgumentError) { GoogleSignIn::Identity.new("some_fake_token") }
|
8
|
+
end
|
9
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: google_sign_in
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Heinemeier Hansson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: google-id-token
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.3.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.15'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.15'
|
55
|
+
description:
|
56
|
+
email: david@basecamp.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- Gemfile
|
62
|
+
- Gemfile.lock
|
63
|
+
- MIT-LICENSE
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- google_sign_in.gemspec
|
67
|
+
- lib/google_sign_in.rb
|
68
|
+
- lib/google_sign_in/helper.rb
|
69
|
+
- lib/google_sign_in/identity.rb
|
70
|
+
- lib/google_sign_in/railtie.rb
|
71
|
+
- test/identity_test.rb
|
72
|
+
- test/test_helper.rb
|
73
|
+
homepage: https://github.com/basecamp/google_sign_in
|
74
|
+
licenses:
|
75
|
+
- MIT
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.9.3
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 2.6.11
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: Sign in (or up) with Google for Rails applications
|
97
|
+
test_files:
|
98
|
+
- test/identity_test.rb
|
99
|
+
- test/test_helper.rb
|