|
1 | 1 | # Google Sign-In for Rails
|
2 | 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. |
| 3 | +This gem allows you to add Google sign-in to your Rails app. You can let users sign up for and sign in to your service |
| 4 | +with their Google accounts. |
6 | 5 |
|
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 | 6 |
|
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>` |
| 7 | +## Installation |
12 | 8 |
|
13 |
| -Now you can use the sign-in integration on your signup or signin screen. |
| 9 | +Add `google_sign_in` to your Rails app’s Gemfile and run `bundle install`: |
14 | 10 |
|
15 |
| -## Example |
| 11 | +```ruby |
| 12 | +gem 'google_sign_in' |
| 13 | +``` |
| 14 | + |
| 15 | + |
| 16 | +## Configuration |
| 17 | + |
| 18 | +First, set up an OAuth 2.0 Client ID in the Google API Console: |
| 19 | + |
| 20 | +1. Go to the [API Console](https://console.developers.google.com/apis/credentials). |
| 21 | + |
| 22 | +2. In the projects menu at the top of the page, ensure the correct project is selected or create a new one. |
| 23 | + |
| 24 | +3. In the left-side navigation menu, choose APIs & Services → Credentials. |
| 25 | + |
| 26 | +4. Click the button labeled “Create credentials.” In the menu that appears, choose to create an **OAuth client ID**. |
| 27 | + |
| 28 | +5. When prompted to select an application type, select **Web application**. |
| 29 | + |
| 30 | +6. Enter your application’s name. |
16 | 31 |
|
17 |
| -Here's the most basic example: |
| 32 | +7. This gem adds a single OAuth callback to your app at `/google_sign_in/callback`. Under **Authorized redirect URIs**, |
| 33 | + add that callback for your application’s domain: for example, `https://example.com/google_sign_in/callback`. |
| 34 | + |
| 35 | + To use Google sign-in in development, you’ll need to add another redirect URI for your local environment, like |
| 36 | + `http://localhost:3000/google_sign_in/callback`. For security reasons, we recommend using a separate |
| 37 | + client ID for local development. Repeat these instructions to set up a new client ID for development. |
| 38 | + |
| 39 | +8. Click the button labeled “Create.” You’ll be presented with a client ID and client secret. Save these. |
| 40 | + |
| 41 | +With your client ID set up, configure your Rails application. In a new initializer, provide the client ID and client secret: |
| 42 | + |
| 43 | +```ruby |
| 44 | +# config/initializers/google_sign_in.rb |
| 45 | +Rails.application.configure do |
| 46 | + config.google_sign_in.client_id = '...' |
| 47 | + config.google_sign_in.client_secret = '...' |
| 48 | +end |
| 49 | +``` |
| 50 | + |
| 51 | +**⚠️ Important:** Take care to protect your client secret. Consider storing your Google client ID and client secret in |
| 52 | +your Rails application’s [encrypted credentials file](https://guides.rubyonrails.org/security.html#custom-credentials): |
| 53 | + |
| 54 | +```yaml |
| 55 | +# rails credentials:edit |
| 56 | +google_sign_in_client_id: ... |
| 57 | +google_sign_in_client_secret: ... |
| 58 | +``` |
18 | 59 |
|
19 | 60 | ```ruby
|
20 |
| -# app/views/layouts/application.html.erb |
21 |
| -<html> |
22 |
| -<head> |
23 |
| -<% # Required for google_sign_in to add the Google JS assets and meta tags! %> |
24 |
| -<%= yield :head %> |
25 |
| -</head> |
26 |
| -<body> |
27 |
| -<%= yield %> |
28 |
| -</body> |
29 |
| -</html> |
30 |
| - |
31 |
| -# app/views/sessions/new.html.erb |
32 |
| -<%= google_sign_in(url: session_path) do %> |
33 |
| - # You can replace this with whatever design you please for the button. |
34 |
| - # You should follow Google's brand guidelines for Google Sign-In, though: |
35 |
| - # https://developers.google.com/identity/branding-guidelines |
36 |
| - <%= button_tag("Signin with Google") %> |
| 61 | +# config/initializers/google_sign_in.rb |
| 62 | +Rails.application.configure do |
| 63 | + config.google_sign_in.client_id = Rails.application.credentials.google_sign_in_client_id |
| 64 | + config.google_sign_in.client_secret = Rails.application.credentials.google_sign_in_client_secret |
| 65 | +end |
| 66 | +``` |
| 67 | + |
| 68 | +Alternatively, provide the client ID and client secret using ENV variables: |
| 69 | + |
| 70 | +```ruby |
| 71 | +# config/initializers/google_sign_in.rb |
| 72 | +Rails.application.configure do |
| 73 | + config.google_sign_in.client_id = ENV['google_sign_in_client_id'] |
| 74 | + config.google_sign_in.client_secret = ENV['google_sign_in_client_secret'] |
| 75 | +end |
| 76 | +``` |
| 77 | + |
| 78 | +## Usage |
| 79 | + |
| 80 | +This gem provides a `google_sign_in_button` helper. It generates a button which initiates Google sign-in: |
| 81 | + |
| 82 | +```erb |
| 83 | +<%= google_sign_in_button 'Sign in with my Google account', proceed_to: create_login_url %> |
| 84 | +
|
| 85 | +<%= google_sign_in_button image_tag('google_logo.png', alt: 'Google'), proceed_to: create_login_url %> |
| 86 | +
|
| 87 | +<%= google_sign_in_button proceed_to: create_login_url do %> |
| 88 | + Sign in with my <%= image_tag('google_logo.png', alt: 'Google') %> account |
37 | 89 | <% end %>
|
38 | 90 | ```
|
39 | 91 |
|
40 |
| -The `url` option is the URL that the hidden form will be submitted against along with the Google ID Token |
41 |
| -that's set after the user has picked the account and authenticated in the pop-up window Google provides. |
| 92 | +The `proceed_to` argument is required. After authenticating with Google, the gem redirects to `proceed_to`, providing |
| 93 | +a Google ID token in `flash[:google_sign_in_token]`. Your application decides what to do with it: |
42 | 94 |
|
43 |
| -You can then use that in a sessions controller like so: |
| 95 | +```ruby |
| 96 | +# config/routes.rb |
| 97 | +Rails.application.routes.draw do |
| 98 | + # ... |
| 99 | + get 'login', to: 'logins#new' |
| 100 | + get 'login/create', to: 'logins#create', as: :create_login |
| 101 | +end |
| 102 | +``` |
44 | 103 |
|
45 | 104 | ```ruby
|
46 |
| -class SessionsController < ApplicationController |
| 105 | +# app/controllers/logins_controller.rb |
| 106 | +class LoginsController < ApplicationController |
47 | 107 | def new
|
48 | 108 | end
|
49 | 109 |
|
50 | 110 | def create
|
51 |
| - if user = authenticate_via_google |
| 111 | + if user = authenticate_with_google |
52 | 112 | cookies.signed[:user_id] = user.id
|
53 | 113 | redirect_to user
|
54 | 114 | else
|
55 |
| - redirect_to new_session_url, alert: "authentication_failed" |
| 115 | + redirect_to new_session_url, alert: 'authentication_failed' |
56 | 116 | end
|
57 | 117 | end
|
58 | 118 |
|
59 | 119 | private
|
60 |
| - def authenticate_via_google |
61 |
| - if params[:google_id_token].present? |
62 |
| - User.find_by google_id: GoogleSignIn::Identity.new(params[:google_id_token]).user_id |
| 120 | + def authenticate_with_google |
| 121 | + if flash[:google_sign_in_token].present? |
| 122 | + User.find_by google_id: GoogleSignIn::Identity.new(flash[:google_sign_in_token]).user_id |
63 | 123 | end
|
64 | 124 | end
|
65 | 125 | end
|
66 | 126 | ```
|
67 | 127 |
|
68 |
| -(This example assumes that a user has already signed up for your service using Google Sign-In and that |
69 |
| -you're storing the Google user id in the `User#google_id` attribute). |
| 128 | +(The above example assumes the user has already signed up for your service and that you’re storing their Google user ID |
| 129 | +in the `User#google_id` attribute.) |
| 130 | + |
| 131 | +The `GoogleSignIn::Identity` class decodes and verifies the integrity of a Google ID token. It exposes the profile |
| 132 | +information contained in the token via the following instance methods: |
| 133 | + |
| 134 | +* `name` |
| 135 | + |
| 136 | +* `email_address` |
| 137 | + |
| 138 | +* `user_id`: A value that uniquely identifies a single Google user. Use this, not `email_address`, to associate a |
| 139 | + Google user with an application user. A Google user’s email address may change, but their `user_id` will remain constant. |
| 140 | + |
| 141 | +* `email_verified?` |
70 | 142 |
|
71 |
| -That's it! You can checkout the `GoogleSignIn::Identity` class for the thin wrapping it provides around |
72 |
| -the decoding of the Google ID Token using the google-id-token library. Interrogating this identity object |
73 |
| -for profile details is particularly helpful when you use Google for signup, as you can get the name, email |
74 |
| -address, avatar url, and locale through it. |
| 143 | +* `avatar_url` |
75 | 144 |
|
76 |
| -## Compatibility with Turbolinks |
| 145 | +* `locale` |
77 | 146 |
|
78 |
| -Google's JavaScript doesn't play nice with Turbolinks. We've routed around the damage by adding a [Turbolinks |
79 |
| -meta tag](https://github.com/turbolinks/turbolinks/blob/master/README.md#ensuring-specific-pages-trigger-a-full-reload) |
80 |
| -on whatever page `google_sign_in` is called to always do a full reload for that page. Note that this |
81 |
| -auto-compatibility feature requires Turbolinks 5.1+. |
82 | 147 |
|
83 | 148 | ## License
|
84 | 149 |
|
|
0 commit comments