i want to uses youtube's api within rails.
I need a client which is able to access youtubes api application wide.
therefore i wrote the following application controller
require 'gdata'
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :auth
def auth
#client = GData::Client::YouTube.new
#client.clientlogin('usermail', 'password')
#client
end
end
i am able to use the client now in my controllers which extend ApplicationController.
thats working fine.
but its pretty slow.
is there a way to do the authentication once and using it application wide instead of suing the before_filter which is getting called every single time before i call a method?
best,
philip
This is a web page. Webpages are state-less. Thus you cannot preserve any state. Thus you cannot preserve your login across requests. Thus you have to auth every request.
An alternative would be to only run the before filter on certain controller actions. Right now it runs on every action, which my be not necessary.
Try:
before_filter :auth, :only=> my_action_name
(P.S. That might be the wrong syntax -- I'm confused 'cause rails changes so much -- just look it up)
Related
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
I've been developing Rails app with REST API for access from mobile application.
It works quite well. When user logs in from mobile application, he gets auth_token that he uses in his future requests to API. The issue is that API is also accessible from web by going to path /api/v1/... and because of this, it has to be protected from CSRF.
I have BaseApiController class which inherits from ApplicationController that has protect_from_forgery "enabled". Here's example:
class Api::V1::BaseApiController < ApplicationController
# ...
end
class ApplicationController < ActionController::Base
protect_from_forgery
# ...
end
Now, when I do non-GET requests to my API, with auth_token, my request gets completed successfully, but in the logs I can see the famous WARNING: Can't verify CSRF token authenticity. If I remove protect_from_forgery from my BaseApiController, I don't get any warnings (obviously), but then my API is vulnerable to CSRF attacks (I made a simple HTML form that successfully changes the data across domains when there's no protect_from_forgery).
My question is: How to assure my API stays secure, but also remove the warning when doing non-GET requests?
Here's one of the solutions I've come up with, but it looks more like a hack and executes one extra DB query:
class Api::V1::BaseApiController < ApplicationController
# ...
def verified_request?
super || User.where(authentication_token: params['auth_token']).count > 0
end
end
More details about the project: Rails 3.2.14, Devise, AngularJS. The project's source code can be found here.
You may see people suggest that CSRF is not an issue for API requests (there is no state to begin with, so what is there to hijack anyhow?), so some suggest the following to simply eliminate the warning:
skip_before_filter :verify_authenticity_token, :only => [:your_method]
However, there was some commentary that it is possible to commit CSRF with text/plain using various Flash and Java-based methods. I believe that was the reason for the security patch in rails a while back: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/
In any event, a good solution that actually checks for an authenticity token can be found here: WARNING: Can't verify CSRF token authenticity rails
It involves actually setting the header in your request.
Good luck!
I would like to use my RoR application to handle both UI and ReSTful API requests, however
I'm running into problems because of the protect_from_forgery flag. I don't want the API user to have to store a cookie or have to pass an authenticity_token; and, I want to be able to use the same ReSTful queries for both the UI and the API. For example,
https://host.domain.com/user/show/1
https://host.domain.com/user/create
The application controller would need to check if an API call is being made and then
not call the protect_from_forgery flag. So something like:
skip_before_filter :verify_authenticity_token, :only => :api
But here :api is an action and I would need to map a new route. I don't think this would allow me to use the same controllers and actions as the UI.
So I'm confused and unsure how to approach this problem. Surely this is a common issue
that many others have had to solve. I appreciate any help that folks could provide.
Here's a yucky idea: skip the before filter, for all actions. Then add a new filter
def verify_authenticity_token_or_api
api? || verify_authenticity_token
end
In your api method, work out whether the request is an api request. Be careful to not allow people to bypass forgery protection by making requests that look a bit like api requests - you might want to do something like invalidate the user's session if there is something that looks like a api request.
Another approach is just to have dedicated endpoints and controllers for your apis. While the stuff rails gets you for free is appealing, sometimes the resources you want to expose don't correspond exactly to your models
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.
I am designing an API system in Ruby-on-Rails, and I want to be able to log queries and authenticate users.
However, I do not have a traditional login system, I want to use an APIkey and a signature that users can submit in the HTTP headers in the request. (Similar to how Amazon's services work)
Instead of requesting /users/12345/photos/create I want to be able to request /photos/create and submit a header that says X-APIKey: 12345 and then validate the request with a signature.
Are there any gems that can be adapted to do that? Or better yet, any gems that do this without adaptation?
Or do you feel that it would be wiser to just have them send the API key in each request using the POST/GET vars?
You probably use an authentication library already. It probably has a way to override the way it checks for authentication. Most likely, the method is named authenticated?. Refer to the documentation for the library you are using, though.
I would not have looked for an existing gem, but implemented it myself; doing so shouldn't be too hard. Here's an example boilerplate implementation:
class ApplicationController < ActionController::Base
def authenticated?
current_user.is_a?(User)
end
def current_user
user_from_session || user_from_api_key
end
def user_from_session
# ... use session[:user] or whatever.
end
def user_from_api_key
User.find_by_api_key(request.headers["X-APIKey"])
end
end
That's as specific as I can get, since you don't say anything about your current authentication setup.