My API uses OAuth2 with Doorkeeper and authentication at the UI level is with Devise.
My app is made up of plain ol' slim files but I need to add an autocomplete search input which sends the query to one of the API endpoints via AJAX.
The user is authenticated via devise session and available as current_user but since the API endpoint is protected with before_action :doorkeeper_authorize! I get a 401.
Is there anyway to "bypass" the doorkeeper_authorize! is the user is already authenticated via Devise?
One option is to copy the action out of the API controller and add in my "normal" UI centric controller which is just protected with Devise but that's just ugly.
Here's a solution I used that worked for me.
before_filter :doorkeeper_authorize!, :unless => :logged_in?
I'm not using devise so I'm not familiar with the methods used for checking authentication, but I have a logged_in? method on my application_controller that will return true if the user is authenticated locally (via cookie). This short-circuits any of the Oauth checking.
Related
I'm developing a Rails app along with a corresponding API and contemplating introducing Ember for some particularly dynamic front end components. I'm using Devise for authentication and Doorkeeper to secure API endpoints and manage OAuth tokens.
I don't want to replace the login piece with Ember so the Ember app will likely be initialized once the user logs in on the primary "logged in index" page. I'd like the Ember app to use the public API rather than rendering JSON from my rails-centric controllers, partly for simplicity and partly to force me to keep the API up to date.
Since the user is already logged in, I don't think it makes sense to do the OAuth dance and get a token. Instead I'd like the API to allow requests from clients that have been logged in by Devise (presence of session / cookie). Effectively, you should be able to visit /api/v1/resources.json in a browser once logged in to the app and receive a JSON response. Currently its a 401 Unauthorized.
Does this seem like a reasonable approach? If so, does anyone have experience doing this?
For anyone interested in this in the future, the answer was pretty straightforward:
module Api
module V0
class ApiController < ActionController::Base
before_action :doorkeeper_authorize!, unless: :user_signed_in?
end
end
end
The key part being unless: :user_signed_in?, which is provided by Devise
I am trying to use devise_token_auth with jsonapi-resources. I have it set up where I can create users and sign in, but I cannot figure out how to access a controller that has needs to authenticate a user first. Here is my controller that I am trying to require authentication:
class FriendsController < JSONAPI::ResourceController
include DeviseTokenAuth::Concerns::SetUserByToken
before_action :authenticate_user!
end
When I try localhost:3000/friends, I get a 401 "Authorized users only." error, so I think it works. I think my main problem is Im not sure what to do with the access-token I get when I sign in. I have tried setting it in the header in my request, but still get the same "Authorized users only" error.
Better a late answer than none... devise_token_auth and jsonapi_resources work pretty well for me in a test setup. But, you need to set the request header correctly. It is not enough to transmit the "auth-token" header, you also heave to transmit the "client" token, the "uid" and the "token-type" header as well. Although I'm not entirely sure if the latter is actually required.
Devise token authentication is quite independent of jsonapi-resources. If you can get token authentication working (as explained in this answer, for example: Custom devise api token auth) you can simply extend your controller (or your ApplicationController) with the authentication concern and it should behave as a normal Rails controller would.
I have a web application already built with its own end points. I am using devise for user registrations/login/logout, basically anything user related is using the session cookies. In the same application, I have separate endpoints for my rails API (used for its mobile application counter part). This API uses authorization tokens (and overriding some Devise methods like current_user) to allow access to the specific user model.
Is this going to give me problems down the line, if I am handling the user session cookies on our website but using authorization tokens on the mobile application? My biggest fear is security issues because we are going to be handling credit card information. The idea is to not use the user session cookies on the mobile application, but keep the web application the same.
The reason I am asking this is because I am having some trouble "logging in" on our web application if I make the web app go through our rails api end points. I am not sure how to safely carry the authorization token from one page to another so I don't make the user login every time.
I hope the way I explained it isn't too confusing.
What about disabling cookies for your Api namespace? If, for example, you're using a BaseController.rb, you can add:
class Api::V1::BaseController < ApplicationController
protect_from_forgery with: :null_session
before_action :destroy_session
def destroy_session
request.session_options[:skip] = true
end
end
As a RoR newbie, I'm using the rails-stripe-membership-saas code (https://github.com/RailsApps/rails-stripe-membership-saas) for my application's base (using Devise for authentication) and attempting to integrate into it the ruby-box gem (https://github.com/attachmentsme/ruby-box) for access to the Box API.
I'm running into what I believe to be conflicts between the Devise session and the subsequent ruby-box (OAuth2) session. My user model contains:
# :omniauthable
devise :database_authenticatable, :registrerable, :recoverable, :rememberable, :trackable, :validatable
After a user logs in, I'm redirecting them to Box to allow them to grant access to my application. This is handled in my application_controller and currently works as such,
def after_sign_in_path_for(resource)
case current_user.roles.first.name
when 'silver'
require 'ruby-box'
session = RubyBox::Session.new({client_id: '###',
client_secret: '###'})
authorize_url = session.authorize_url('https://myurl.com/auth/box')
end
end
Once the user grants access to my app, they are redirected to my Box controller (auth/box), where I'm attempting to get the access token from Box based on the code they provided in the redirect,
class BoxController < ApplicationController
def new
#token = session.get_access_token('code-returned-to-redirect_url')
end
end
This is when I run into the issue, getting the error:
undefined method 'get_access_token' for #<Rack::Session::Abstract::SessionHash:0x0000003b4cf00>
I can only assume that in calling "session" its not able to distinguish between the current user session and the Box session? How can I correct for this?
Thanks for your time and assistance.
I'm not particularly familiar with ruby-box, but it appears that their Session class is confusingly named. The Rails session object, accessible from controllers, is a way of managing persistent state across requests for a user -- a typical use of the word "session." But a ruby box session is nothing of the sort; it appears to just be a plain old ruby object with an API for making oauth authorization requests to ruby box.
The key is that there is no persistence of any RubyBox::Session object between requests. So when you redirect the user after sign in, the local variable session you created in after_sign_in_path_for is no longer available. So when you refer to session in your BoxController, you're getting an actual session object, not a RubyBox::Session.
The workflow that you're attempting isn't designed for an Authorization Code oauth grant type (the kind where a user of your application explicitly authorizes access to some protected resource they own, and you exchange an authorization code for an access token). It appears that it's designed for the Client Credentials authorization grant. That is, you're just getting a token based on your client key and client secret, where the authorization to access protected resources is implicit after you've authenticated your client.
Edited to add: if you want to authenticate your users via Box, you should have a look at omniauth-box instead, which will help you easily implement the authorization code oauth flow and will play nicely with devise.
So it appears that the documentation you're following isn't designed for the use case you have in mind. But as for the sessions, yeah, the session helper in a Rails controller refers to the users's session data that is persistent across requests, not a RubyBox::Session object.
I am building an API for my rails app i am trying to reuse same controllers for both API and app logic. The requests without authenticating a user is fine but how to implement if some actions need an authentication. I am using authlogic, to edit people need some specific permissions which i am checking in the before_filter. If i implement an API using http basic authentication how do i differentiate ?
I think there are two parts to the answer. Firstly you need to set up http basic auth with authlogic. The details for doing that are contained in this SO answer: Rails: Basic Authentication with Authlogic
Then you need to differentiate between API calls and normal browser calls in your controller. Assuming your API is XML or JSON, you can do that with something like this:
class ThingsController < ApplicationController
before_filter :authorize
def authorize
if params[:format] == 'json' || params[:format] == 'xml'
require_http_auth_user # http basic auth for API access
else
require_user # normal authlogic authentication
end
end
end
It may be worthwhile separating into two separate controllers and including the common functionality via a mixin. That way you can auth the controllers separately.