Rails 8 Devise and OAuth Issue: Login Page Reappears After Back Button, Raises InvalidAuthenticityToken - Stack Overflow

I’m using Rails 8 with Devise for authentication and have encountered an issue with OAuth (Google, GitH

I’m using Rails 8 with Devise for authentication and have encountered an issue with OAuth (Google, GitHub) sign-in behavior. Here’s the observed behavior:

Good Working Scenario: Email Sign-In

  1. When a user clicks a link (e.g., /blogs) that requires authentication, they are redirected to the login page.
  2. The user enters their email and password. If the credentials are valid, they are redirected to the /blogs page.
  3. If the user presses the browser’s back button while on the /blogs page, the app redirects the user to the home page and correctly displays the flash message: "You are already signed in".

Problematic Scenario: OAuth (Google) Sign-In

  1. When a user clicks a link (e.g., /blogs) that requires authentication, they are redirected to the login page.
  2. The user clicks the "Sign in with Google" button, completes the OAuth process, and is redirected to the /blogs page.
  3. If the user presses the browser’s back button while on the /blogs page:
    • The login page reappears instead of redirecting them to the home page and displaying the flash message: "You are already signed in."
    • If the user clicks the "Sign in with Google" button again, it raises an ActionController::InvalidAuthenticityToken error.

Question

How can I handle OAuth sign-in in Rails 8 with Devise so that, if the user is already signed in via OAuth, the app redirects to the home page with a flash message ("You are already signed in") when the user navigates back to the login page (e.g., by clicking the back button), without needing to refresh the page?

Additional Context

Here's my OmniauthCallbacksController:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def github
    handle_auth("GitHub")
  end

  def google_oauth2
    handle_auth("Google")
  end

  def handle_auth(kind)
    @user = User.from_omniauth(request.env["omniauth.auth"])

    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication
      set_flash_message(:notice, :success, kind: kind) if is_navigational_format?
    else
      session["devise.#{kind.downcase}_data"] = request.env["omniauth.auth"].except(:extra)
      redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
    end
  end
end

the user.rb:

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :confirmable, :trackable, :omniauthable, omniauth_providers: [ :github, :google_oauth2 ]

  # handle OmniAuth callbacks
  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.email = auth.info.email
      user.password = Devise.friendly_token[0, 20] # Generate a random password
      user.first_name = auth.info.first_name || auth.info.name
      user.last_name = auth.info.last_name

      # Bypass confirmation by setting `confirmed_at` to the current time
      user.confirmed_at = Time.current
    end
  end
end

and the button for the Google sign in:

= button_to user_google_oauth2_omniauth_authorize_path,
            class: "btn btn-social w-100",
            "data-turbo" => false do
  %span.icon-holder
    =  image_tag("social/google-logo.svg")
  %span.btn-text Sign in with Google

I’ve already tried the following approaches:

  1. Overriding the SessionsController#new Method: I tried overriding Devise::SessionsController#new to redirect already-signed-in users from the login page, but it didn’t resolve the behavior with OAuth.
class Users::SessionsController < Devise::SessionsController
  def new
    if user_signed_in?
      redirect_to root_path, notice: "You are already signed in." and return
    end
    super
  end
end
  1. Adding Cache-Control Headers: I added Cache-Control headers to prevent the browser from caching the login page, but it didn’t fix the issue.
class ApplicationController < ActionController::Base
  # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
  allow_browser versions: :modern
  before_action :authenticate_user!
  before_action :set_no_cache_headers, if: :devise_controller?

  protected

  def set_no_cache_headers
    response.headers["Cache-Control"] = "no-cache, no-store"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "0"
  end
end

Currently, I’ve worked around the issue by adding Cache-Control headers to the root page. While this solution works, I’m hoping there’s a better approach.

class HomeController < ApplicationController
  before_action :set_no_cache_headers, only: [ :index ]
  skip_before_action :authenticate_user!

  def index
    @categories = Category.all

    # popular topics
    @topics = Topic.order(id: :desc).limit(8)
  end
end

Any insights or solutions would be greatly appreciated!

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745564729a4633323.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信