0

I am using token based authentication system for my APIs which is built based on Devise. The user is authorised to access the pages only when the email and mobile number linked with his/her account has been verified. If anyone of the above is not verified, the user gets the 403 access forbidden error message.

def authenticate_user!
    unless current_user
      authorization_failed_error
    end
    if current_user.confirmed_at.blank?
      unconfirmed_email_error
    elsif current_user.mobile_confirmed_at.blank?
      unconfirmed_mobile_error
    end
end

When an user with a unconfirmed email is trying to access a content through the API, error message is thrown. But if the same user tries for the second time, Devise redirects the user to the login view page.

Above scenarios occur alternatively every time.

current_user is set by the set_user_by_token function of the Devise, as below.

def set_user_by_token(mappings=nil)
    rc = resource_class(:user)
    # no default user defined
    return unless rc

    #gets the headers names, which was set in the initialize file
    uid_name = 'Uid'
    access_token_name = 'Access-Token'
    client_name = 'Client'
    expiry_name = 'Expiry'

    # parse header for values necessary for authentication
    uid        = request.headers[uid_name] || params[uid_name]
    @token     ||= request.headers[access_token_name] || params[access_token_name]
    @client_id ||= request.headers[client_name] || params[client_name]

    # client_id isn't required, set to 'default' if absent
    @client_id ||= 'default'

    # check for an existing user, authenticated via warden/devise, if enabled
    devise_warden_user = warden.user(rc.to_s.underscore.to_sym)
    if devise_warden_user && devise_warden_user.tokens[@client_id].nil?
      @used_auth_by_token = false
      @resource = devise_warden_user
      @resource.create_new_auth_token
    end

    # user has already been found and authenticated
    return @resource if @resource and @resource.class == rc

    # ensure we clear the client_id
    if !@token
      @client_id = nil
      return
    end

    return false unless @token

    # mitigate timing attacks by finding by uid instead of auth token
    user = uid && rc.find_by_email(uid)

    if user && user.valid_token?(@token, @client_id)
      # sign_in with bypass: true will be deprecated in the next version of Devise
      if self.respond_to? :bypass_sign_in
        bypass_sign_in(user, scope: :user)
      else
        sign_in(:user, user, store: false, bypass: true)
      end
      @resource = user
      return @resource
    else
      # zero all values previously set values
      @client_id = nil
      return @resource = nil
    end
 end

I am not sure why Devise(or Warden) behaves like this every second time. It would be of great help if someone could figure this out.

  • Just a observation you should not use `and` unless you have a really good reason to you should replace with `&&`. – C dot StrifeVII Oct 24 '16 at 13:07
  • and this question/answer explains the difference: http://stackoverflow.com/questions/1426826/difference-between-and-and-in-ruby – jaydel Oct 24 '16 at 14:16
  • Thanks for your response guys. But for your kind information, the function set_user_by_token is the native function of the devise gem. I haven't altered anything with regard to the operators – arparthasarathi Oct 25 '16 at 05:53

0 Answers0