Masroor
Masroor

Reputation: 1604

How to send sign in info to frontend after successful Oauth2 authorization in devise_token_auth?

I'm using devise_token_auth for Email and Google Oauth2 based authentication(used omniauth-google-oauth2 gem for this). I've successfully managed to store sign in info of the user signing up/in through Google Oauth2 flow. The info includes:

{"auth_token"=>"token here", "client_id"=>"client id here", "uid"=>"uid here", "expiry"=>1620492005, "config"=>nil, "oauth_registration"=>true}

The flow for the above info was

  1. Visit http://localhost:3000/auth/google_oauth2. This redirects you to the Google auth screen
  2. User selects account and grants permission.
  3. Oauth success callback from my app is executed at http://localhost:3000/auth/google_oauth2/callback

The code which executes for the first step is

module DeviseTokenAuth
  class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
    attr_reader :auth_params

    before_action :validate_auth_origin_url_param
    
    def omniauth_success
      get_resource_from_auth_hash
      set_token_on_resource
      create_auth_params

      if confirmable_enabled?
        # don't send confirmation email!!!
        @resource.skip_confirmation!
      end

      sign_in(:user, @resource, store: false, bypass: false)

      @resource.save!

      yield @resource if block_given?

      render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json)
    end
  end
end

Problems I'm facing:

  1. sign_in method call does not set @current_user despite that @resource and @auth_params have all the necessary info in them.
  2. How can I inform my frontend app about the sign in info(token, client_id, uid)?
render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json)

this call does not redirect or render anything, instead it stays on the same page the URL it shows is http://localhost:3000/auth/google_oauth2/callback#

I basically have three questions now:

  1. How can I use devise_token_auth to set the current_user based on the incoming auth headers? I have added the following line to my controller, but still it fails to set @current_user
include DeviseTokenAuth::Concerns::SetUserByToken

maybe it is because I'm sending auth headers incorrectly? See my 3rd point below for this.

  1. How am I supposed to send the sign in info to my frontend app? Do I modify the above method somehow to send sign in info to my frontend app?

  2. What and where do I put the auth headers in order to make authenticated requests?

I have used postman to test both of the following but it failed with Unauthorized error

  1. Sent access-token, client_id and uid in headers
  2. Sent Bearer my_token in authorization headers.

Upvotes: 1

Views: 384

Answers (1)

Masroor
Masroor

Reputation: 1604

To get this working, we had to override the DeviseTokenAuth's OmniAuthCallbacks controller and update its render_data_or_redirect method.

The default definition of render_data_or_redirect is

def render_data_or_redirect(message, data, user_data = {})
  if ['inAppBrowser', 'newWindow'].include?(omniauth_window_type)
    render_data(message, user_data.merge(data))
  elsif auth_origin_url

    redirect_to DeviseTokenAuth::Url.generate(auth_origin_url, data.merge(blank: true))
  else
    fallback_render data[:error] || 'An error occurred'
  end
end

The following routes.rb and custom_omniauth_callbacks_controller.rb have the changes needed to be done to get it working with j-toker library.

In the routes file

# config/routes.rb

mount_devise_token_auth_for 'User', at: 'auth', controllers: {
  omniauth_callbacks: "devise_token_auth/custom_omniauth_callbacks"
}

and the definition of CustomOmniAuthCallbacksController was

# app/controllers/devise_token_auth/custom_omniauth_callbacks_controller.rb

module DeviseTokenAuth
  class CustomOmniauthCallbacksController < DeviseTokenAuth::OmniauthCallbacksController
    protected

    def render_data_or_redirect(message, data, user_data = {})
      if (['inAppBrowser', 'newWindow'].include?(omniauth_window_type) || auth_origin_url)

        redirect_to DeviseTokenAuth::Url.generate(auth_origin_url, data.merge(blank: true))
      else
        fallback_render data[:error] || 'An error occurred'
      end
    end
  end
end

now on the front-end side you need to configure j-toker

First, install j-toker package, yarn package or npm package

yarn add j-toker

or

npm i j-toker

then in your javascript application, configure the j-toker

import $ from "jquery";

$.auth.configure({
    apiUrl: "https://your-api-domain.com",
    emailSignInPath: "/auth/sign_in",
    signOutPath: "/auth/sign_out",
    emailRegistrationPath: "/auth",
    tokenValidationPath: "/auth/validate_token"

    authProviderPaths: {
      facebook: "/auth/facebook",
      google: "/auth/google_oauth2"
    }
  });

Upvotes: 1

Related Questions