How do I authenticate using Devise in a Rails REST API App? - ruby-on-rails

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?

Related

Ruby on Rails Google Api Authentication

So, I'm very new to this. I got a generated json file from my google developer console that holds information like private keys, client id, token stuff, etc.
Now, I'm trying to use the Google Analytics Report V4 api. I put all my code into a concern, and when I run the code I get this error:
Google::Apis::AuthorizationError: Unauthorized
So I know that I have to authorize my app, but I'm not sure how. I have this json file which appears to have all the information I need to authenticate my app.
After some research, I know that (on the following code) I need to assign analytics.authorization to something, I just don't know to what.
analytics = Google::Apis::AnalyticsreportingV4::AnalyticsReportingService.new
analytics.authorization = ???
Do you know of any method I'm supposed to call that takes in the location of my json file as a parameter or something that can in turn, authorize my rails app?
Thank you so so much if you can help.
I know there are other questions like this. But they use omniauth with devise I think, and I can't do that. I already have a specific context in which users need to be logged in to my app, so logging in with google wouldn't work in my case. Also, other question/answers that don't involve omniauth and devise are outdated or don't have an accepted answer.

How to validate that a user owns the requested resource through Rails API when using devise_token_auth

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.

Using the new Devise for authentication for a mobile app

I am trying to implement user authentication using Devise for my Rails/iOS app. I am having trouble since I've mostly been a "user" of Devise and was using it for pure web apps so didn't need to bother so much with what goes on behind the scenes. Now that I have to build authentication for an API based app, it's entirely a different world.
I've read every single tutorial on the web that deals with this topic (most of them are outdated due to the fact that token_authenticatable has been deprecated) but still having trouble understanding what I need to do.
I also read the original GitHub gist talking about this issue and still don't understand what they are talking about.
I'm sure there are people out there just like me who've been just a "user" of Devise so don't really know what goes on behind the scenes.
Can anyone provide a concise solution to implementing an API based authentication system for a mobile app? I mean it can't be that complex, Devise used to be so awesome since all i needed to do was run rails generate, but this has been nightmare for me.
I am working on same things as you want,
for this you have to use token authentication rather than simple
Devise, add following gem in gemfile
# Use device for authentication
gem 'devise'
gem 'simple_token_authentication'
follow documention simple_token_authentication
Use Api like this
curl -v https://example.com/users/sign_in -X POST -H "Accept: application/json" -H "Content-Type: application/json" -d '{"user": {"login": "7838712847" ,"password": "8489", "mobile_type": "ios", "mobile_key": "APA91bG6G4UvjeCWvb8mMAH1ZO3I-8FB3nkRPyCHnwZiXgd16HK18GgoV5n7gjJtZNs038iaFGutzdxnhes3WyaXEX52-xmOyvuEK8S1abBdpuhD9AD5bzLWeu-1Ow_yZRTVg3Nypz1z"}}'
I am using mobile number to login so customize gem according your need
please let me know if it is not working (mail me: er.mukeshsharma.rj21#gmail.com)
Here is an approach that works excellent for me, when using Devise for authentication in a Rails app. If tests for a token first (you can set the token by any iOS, Android, ... app) and falls back to the default authentication method for your web users.
Rails
Add your own token to the user model, by adding an :api_token string column and fill that with a unique value per user. Using a Digest::SHA1 of some user data (like id + email) is a good starting point, but you can (and should) go as crazy as you like when it comes to generating a unique token.
Create a method for authentication over that token. You can add it to your main ApplicationController for easy access (don't forget to put the method in your private section of the controller);
def authenticate_user_by_token
#api_token = request.headers['HTTP_AUTHORIZATION']
if #api_token.present? && #user = User.find_by_api_token(#api_token)
sign_in #user
return #user
else
return false
end
end
Next create a (private) method and chain this method to the devise before filter method you are using (like :authenticate_user! for example). Put it in the same controller as the method above for easy access;
def authenticate_by_token_or_devise!
return authenticate_user! unless authenticate_user_by_token
end
Now Replace your current before_filter call from :authenticate_user! to the newly created one; :authenticate_by_token_or_devise!, like so;
before_filter :authenticate_by_token_or_devise!
Or, starting from rails 4 (Rails 4: before_filter vs. before_action), use before_action;
before_action :authenticate_by_token_or_devise!
iOS
Now all you have to do is add that token to your iOS app. Depending on the framework that you use in your app, this might be different then the code below.
I use AFNetworking (https://github.com/AFNetworking/AFNetworking) in this example. This is how you set the Authorisation header token in your AFHTTPRequestOperationManager so it gets added to every request you make.
NSString *apiToken = #"your-token-here";
[[_manager requestSerializer] setValue:apiToken forHTTPHeaderField:#"Authorization"];
Optional
Additionally, you can create a before filter method that allows access to token-based authentication only (e.g. if you have a set of /api routes that you only want to be accessed using the token) like this;
def authenticate_user_by_token!
if !authenticate_user_by_token
render nothing: true, status: :unauthorized and return
end
end
Recently, we also had to set up token based authentication for our webapp (for API access) - and we also stumbled upon the fact that it has been removed from Devise.
We went with Simple Token Authentication which worked just beautifully.
When I recently implemented an API, I grudgingly followed a suggestion to use Warden, a rack-based authentication gem. My sense was that an authentication gem that required you to write your own authentication was broken. But this gem provides just the right level of control. My only complaint is that the gem don't handle POST parameters well. I was able to work around it, but that kind of concern should be (IMO) handled by the gem.
Having used it, I highly recommend this gem for any scenario requiring non-generic authentication. Rolling your own authentication strategies is a joy because (a) it's pretty simple and (b) you aren't bound by other devs' assumptions.
To help you get started, here is my config/initializers/warden.rb file.
You can use a combination of the devise gem and doorkeeper gem to support web and mobile authentication.
For example, I used devise for signing up users and handling forget password and email confirmation flow. For mobile clients, I used the doorkeeper gem as a oauth2 provider to protect my apis. There are many oauth2 grant flows supported by the doorkeeper gem and I suggest you can take a look at those.
Here's a link! to get started

Can't understand scheme of creating API with Devise, RocketPants, Doorkeeper

I was developing website and decided to separate back-end(rails) and front-end(angularjs). All went good until I tried to implement authenticating over JSON. I've found tons of material on how to implement it with devise, or with doorkeeper, but I can't understand how to put it together. (API is implemented with RocketPants)
From what I've realized, from front-end I should send login and pass on init, getting back authtoken (step 1). Then on every call I should send authtoken with other data (step 2)
On step 1: Doorkeeper redirects_to sign_in page. Should I modify controller in way that it should come to controller, which would handle authentication (by using warden.authenticate!) ? And how does Doorkeeper know that I'm logged in since that moment? (for giving me authtoken)
On step 2: Authtokens are individual per user and per application, which uses API, right? So I should somehow specify, from which application request comes, shouldn't I? "
Note: Backend is going to be API only, so everything should be handled by JSON requests. But how I modify available applications then? One more custom controller over Doorkeeper?
Thanks in advance, I hope, I'm not the only one with such questions =)

How do you authenticate user generated "apps" for your app?

I'm think something like Facebook apps here. User generated pieces of code that people can write to interact with my app.
I understand how an authenticated API works, but this seems a little more complicated because not only does the APP have to authenticate itself (with a regular api-key) but the USER using the app has to be authenticated somehow too, without giving the app free reign.
I've been reading a bit here to see how FB does it: http://wiki.developers.facebook.com/index.php/How_Facebook_Authenticates_Your_Application
And it looks like you have to pass a signature in addition to the api-key along with every call, but I'm having trouble wrapping my head around how this gets generated and used on the other end (my server).
Figure there must be a simple explanation of this out there? Thanks!
P.S. I'm building a Rails app if there are any applicable gems/plugins.
This may be what I need:
http://github.com/phurni/authlogic_api
Did you have any success with authlogic_api? I'm working on the server-side for a Steam game, where users are logged in through Steam, so I'm only responding to REST calls from the client (no user login required). The rdocs for authlogic_api give some brief set-up info, but I'm struggling with what to do in the application_controller to restrict access; essentially the equivalent of this code from the authlogic example:
http://github.com/binarylogic/authlogic_example/blob/5819a13477797d758cb6871f475ed1c54bf8a3a7/app/controllers/application_controller.rb

Resources