I have a Rails app with an iOS mobile client.
So far, I've had the iPhone client send HTTP requests to the normal URLs. I want to replace this with a proper API. I'm on Rails 3, and I'm using Authlogic for authentication.
I have watched the railscasts on versioned apis and securing APIs. But since I'm already using authlogic for authentication, I think reimplementing token creation would be unnecessary?
I created the API just as Ryan Bates suggests in this episode with a controller under app/controllers/api/v1/. I have corresponding views with RABL in views/api/v1.
My controller is
module Api
module V1
class RecordsController < ApplicationController
respond_to :json
def index
status = RecordStatus.where("name = ?", "processed").first
#records = current_user.records.where("record_status_id = ?", status.id)
end
def show
#record = Record.find(params[:id])
end
end
end
end
Basically, I've read a lot on the different options to implement (including a bunch of answers on SO) and I'm just really stumped as to what's the best way for me to implement authentication, securely. Should I go to oauth? Can I do it with authlogic? Which option would make it easy to use from the iOS side? Which option is easiest to implement?
Any guidance would be helpful.
Perhaps you could use the single access token stuff that's in authlogic already?
http://rubydoc.info/gems/authlogic/Authlogic/Session/Params
Related
I am building an API-only (for now) Rails app to serve as the back end for an Android app I'm building. I was previously using Firebase but wanted to do more processing on application data and I didn't want to bloat the mobile client with all the logic, so I am moving away from Firebase's real-time database and backing the application data using Rails. I was also using Firebase's authentication which is very straightforward. But it seems less complex for the overall system to keep all of this functionality in one place, so I'd like to perform auth and user management in the Rails app as well.
I have installed devise_token_auth (seen here) and finished the basic configuration. The /auth route works correctly if params are provided and creates a user. sign_in and sign_out both successfully create sessions and return some header information. The important parts returned are client, access-token, and uid, which I need to use in future calls to the API. I believe these are invalidated and replaced with each subsequent call. At this part of the flow is where I'm not sure how to proceed. I don't understand how the data in these headers is associated with the user who signed in and how I can validate that they own a resource they request. To summarize the question another way:
How can I sign a user into the API and then validate which user is making subsequent API calls?
My Android app is a task manager, so I need to be able to validate for example that if user 1 requests task 3, that they own that resource. I'm also unsure how to direct index calls using the API. That is, when the index endpoint is hit (/tasks), how can I identify from the data in the API headers which user's tasks I should retrieve.
I haven't been able to find any solid tutorials or samples using devise_token_auth so I'm having trouble stitching together the interaction between the pieces I have now. I know this is a meaty question - thanks in advance for any guidance.
How can I [...] validate which user is making subsequent API calls?
With the current_user method. This is a built-in feature to the devise_token_auth gem.
I need to be able to validate for example that if user 1 requests task 3, that they own that resource
There are many different approaches you could take. You could just write some custom logic in each controller action, using the current_user method (and return 403 forbidden if necessary).
Or, you could use a popular "framework" solution for this such as CanCanCan or Pundit. I, and probably most of the modern community, would recommend Pundit.
I highly advise you to read that library's README, as it's extremely helpful. But for the example above, you could write something like this:
class TasksController
def show
task = Task.find(params[:id])
authorize(task) # !!!
render task
end
end
# app/policies/task_policy.rb
class TaskPolicy
def show?
record.user == user
end
end
(Note that by default, the "user" in Pundit policies calls the method: current_user. This is all explained in the project's README.)
when the index endpoint is hit (/tasks), how can I identify from the data in the API headers which user's tasks I should retrieve
Again, this is all handled as part of Pundit's standard features. You just need to define a TaskPolicy::Scope and call policy_scope(Task) in the controller - as explained here.
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'm creating a Rails app which have both a GUI part, and a REST/JSON-API.
The REST/JSON API is fairly simple, and the controller returns data like this:
def get_players
#players = Player.all
render json: #players
end
The GUI part of the app is using Devise for authentication, and it works fine.
Now I want to add authentication for the REST/JSON Api too, how do I do that?
Also, how do I test the REST API using curl when the Authentication is added?
---- edit ----
as it turns out, Devise wasnt necessary in this case. A home-cooked token-authentication method works for now. (token created when Player is created, and returned on correct e-mail/password combo).
After getting a few tips, I found a number of great sites. There are several ways to do this, however I don't know which one is best, but these sites help a long way:
https://github.com/lynndylanhurley/devise_token_auth (An extension to
Devise)
https://labs.kollegorna.se/blog/2015/04/build-an-api-now/
(Manual way)
Token based authentication for Rails JSON APIs (SO Question)
Rails API : Best way to implement authentication? (SO Question)
Rails API : Best way to implement authentication?
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.