Google OAuth — Plan

Complexity: Medium Integration: Google OAuth2 login via Devise + OmniAuth


External Setup

  1. Go to Google Cloud Console
  2. Create project (e.g., "Your App Name")
  3. APIs & Services → Library → Enable "People API"
  4. APIs & Services → OAuth consent screen:
    • User type: External
    • App name, support email, developer email
    • Scopes: email, profile, openid
    • Add authorized domain
  5. APIs & Services → Credentials → Create OAuth Client ID:
    • Type: Web application
    • Redirect URIs:
      • https://yourdomain.com/users/auth/google_oauth2/callback
      • http://localhost:3000/users/auth/google_oauth2/callback
    • Note Client ID and Client Secret
  6. (If in testing mode) Add test users under OAuth consent screen

Code Changes

  1. Add to Gemfile:
    gem "omniauth"
    gem "omniauth-google-oauth2"
    gem "omniauth-rails_csrf_protection"
    
  2. bundle install
  3. Add credentials via bin/rails credentials:edit:
    google_oauth:
      client_id: "xxx.apps.googleusercontent.com"
      client_secret: "GOCSPX-xxx"
    
  4. Migration: bin/rails g migration AddOmniauthToUsers provider:string uid:string
    • Add index: add_index :users, [:provider, :uid], unique: true
    • bin/rails db:migrate
  5. Update config/initializers/devise.rb: add config.omniauth :google_oauth2, credentials.dig(:google_oauth, :client_id), credentials.dig(:google_oauth, :client_secret), scope: "email,profile"
  6. Add :omniauthable to Devise modules in app/models/concerns/user/authentication.rb:
    devise :magic_link_authenticatable, :invitable, :database_authenticatable,
           :registerable, :recoverable, :rememberable, :validatable, :trackable,
           :omniauthable, omniauth_providers: [:google_oauth2]
    
  7. Create User::OmniauthHandler namespaced class in app/models/user/omniauth_handler.rb:
    • resolve method: find by provider+uid, or find by email and link, or create new user
  8. Create app/controllers/users/omniauth_callbacks_controller.rb:
    • google_oauth2 action: calls User::OmniauthHandler.new(auth).resolve, signs in, redirects
    • failure action: redirects to sign_in with error
  9. Update config/routes.rb — add to devise_for controllers hash:
    omniauth_callbacks: "users/omniauth_callbacks"
    
  10. Update app/views/devise/shared/_links.html.erb to render OmniAuth provider button with graceful error handling

Verification

  • Visit /users/sign_in → "Sign in with Google" button visible
  • Click → Google OAuth flow → redirected back → signed in
  • Existing user with same email can link Google account
  • New OAuth user gets personal organization created
  • Run bin/ci — existing tests still pass