5 min read + 13 min video Published September 30, 2025

Google Signin with Rails Authentication Generator

Adding Google Signin to a Ruby on Rails app using the authentication generator

📹 Watch the Development Process

Watch the whole video at: youtube.com/watch?v=tCVEMj-D5zI
Source code: github.com/stocklight/insidertrades.directory

🎯 What We Accomplished

🛠️ Tools Demonstrated

🛠 Technical Walk-through

1. Generate Rails Authentication (Passwordless Users table, No Devise / Omniauth)

The Devise plus Omniauth gems add 898kb and 12,900 lines of code to a rails project... And 99% of that code is unnecessary.

Rails now provides an authentication generator which added 535 lines in this commit from the video above. That was generated by Claude Code with --dangerously-skip-permissions using the following prompt:

Generate rails auth using the rails 8 authentication generator (ie. no devise) and put a 'Join mailing list' button in the page header which takes the user a /signin route with a panel on the left that has an email address field and 'Subscribe' button and on the right, has some benefits listed. 

When clicked, it should email a random new 6 digit verification code persisted on the user record (with a verification_code_generated_at column) and redirect them to a /verify route with a form for them to enter the code. When entered correctly within 15 minutes, it signs them in after which the join button becomes a 'Sign Out' button. If entered more than 15 minutes after generated, they get an expired message. Don't persist passwords for users.

2. Set up Google OAuth Client for Google Signin

To prepare to add a google signin button (3:40 in the video above):

  • Create an account on Google Cloud Console and add a credit card (which won't be charged for signin integration)
  • Menu > APIs & Services > OAuth consent screen > Create OAuth client
  • Application type: Web application
  • Authorized Javascript origins: https://your.url + http://localhost:3000 (for testing your dev server)
  • Authorized redirect URIs: https://your.url/google-signin + http://localhost:3000/google-signin (note, whatever you specify here will be the callback url that google will issue a GET request to when users authenticate)
  • Copy the Client ID from your generated OAuth client

3. Integrate Google Signin into the Rails app

Per this git commit:

app/views/sessions/new.html.erb

<div style="margin-bottom: 2rem;">
  <div id="g_id_onload"
    data-client_id="<%= GoogleSignin::WEB_CLIENT_ID %>"
    data-context="signin"
    data-ux_mode="redirect"
    data-login_uri="<%= google_signin_url %>"
    data-auto_prompt="false"
    data-itp_support="true">
  </div>

  <div class="g_id_signin"
    data-type="standard"
    data-shape="rectangular"
    data-theme="outline"
    data-text="continue_with"
    data-size="large"
    data-logo_alignment="left">
  </div>

  <% content_for(:head) do %>
    <script src="https://accounts.google.com/gsi/client" async defer></script>
  <% end %>
config/routes.rb
post "google-signin", to: "sessions#create_for_google", as: :google_signin
app/controllers/sessions_controller.rb
    
def create_for_google
  google_signin = GoogleSignin.new(web_credential: params[:credential])

  if google_signin.valid?
    # Find or create user by email
    user = User.find_or_initialize_by(email_address: google_signin.email)
    user.google_user_id ||= google_signin.user_id
    user.first_name ||= google_signin.first_name
    user.last_name ||= google_signin.last_name
    user.photo_url ||= google_signin.photo_url
    user.save!
    
    # Sign them in
    start_new_session_for(user)
    
    flash[:notice] = "Successfully signed in with Google!"
    redirect_to root_path
  else
    flash[:alert] = "Could not authenticate you from Google"
    redirect_to signin_path
  end
rescue => e
  Rails.logger.error "Google signin error: #{e.message}"
  flash[:alert] = "Could not authenticate you from Google"
  redirect_to signin_path
end
app/models/google_signin.rb

class GoogleSignin
  attr_reader :email, :first_name, :last_name, :photo_url, :user_id

  # Your provided client ID
  WEB_CLIENT_ID = "THE-OAUTH-CLIENT-ID-FROM-GOOGLE-CLOUD-CONSOLE"

  def initialize(web_credential:)
    @web_credential = web_credential
    @client_id = WEB_CLIENT_ID
  end
  
  def valid?
    return false if @web_credential.blank?

    validated_token = GoogleIdTokenValidator.validate(
      token: @web_credential,
      client_id: @client_id,
    ).stringify_keys

    @email = validated_token['email']
    @first_name = validated_token['given_name']
    @last_name = validated_token['family_name']
    @photo_url = validated_token['picture']
    @user_id = validated_token['sub']
    
    @email.present?
  rescue => e
    Rails.logger.error "Google signin validation failed: #{e.message}"
    false
  end
end
app/models/google_id_token_validator.rb

require 'net/http'
require 'json'
require 'jwt'

class GoogleIdTokenValidator
  GOOGLE_JWKS_URI = 'https://www.googleapis.com/oauth2/v3/certs'
  GOOGLE_ISSUER = 'https://accounts.google.com'

  def self.validate(token:, client_id:)
    # Fetch the JWT header without verification
    header = JWT.decode(token, nil, false)[1]
    kid = header['kid']

    # Fetch Google's public keys
    uri = URI(GOOGLE_JWKS_URI)
    response = Net::HTTP.get_response(uri)
    jwks = JSON.parse(response.body)
    
    # Find the key that matches our token's kid
    public_key = nil
    jwks['keys'].each do |key|
      if key['kid'] == kid
        public_key = JWT::JWK.import(key).public_key
        break
      end
    end

    raise 'No matching key found' unless public_key

    # Verify the token
    decoded_token = JWT.decode(
      token,
      public_key,
      true,
      {
        algorithm: 'RS256',
        verify_iss: true,
        iss: GOOGLE_ISSUER,
        verify_aud: true,
        aud: client_id,
        verify_iat: true
      }
    )

    # Return the payload
    decoded_token.first
  rescue JWT::DecodeError, OpenSSL::PKey::RSAError => e
    raise "Token validation failed: #{e.message}"
  end
end
🎉 Google Signin Ready! Your rails app now has a google signin button and a working google signin flow.

🔗 Resources & Technologies

Authentication Technologies
Related Posts
Sep 29, 2025
Google Signin with Rails Authentication Generator
Coming Soon
Exception Notifier with Slack integration
Coming Soon
Turbolinks / View Component, no webpacker node or js
← Back to All Posts