API Access with Devise Authentication - Best Practices? - ruby-on-rails

I'm using Devise in a Rails app and want to expose some of the model data via an API, but access to the API should be restricted just like the app.
$ curl http://myapp.com/api/v1/sales/7.json
{"error":"You need to sign in or sign up before continuing."}
Obviously.
Is there a best practice for accessing the API in situations like this? I'd prefer to authenticate + grab the data in one step, but that's just to make the client's job easier. They'll be pulling in the data client-side with JQuery.
Thanks for any info!
Vanessa

I recommend you follow the Option 2: Using API Key section on the following post to implement API authentication in Rails.
http://www.whatcodecraves.com/articles/2008/11/25/how_to_make_an_api_for_a_rails_app/
It's lightweight and simply requires passing an api_key param with each request.

My suggestion would to generate an API "key" (hash value) and have that passed with the json request. That way you can authenticate and track API use. A lot of APIs use "keys" to track and authenticate use. Google maps for instance, they use just an API key. Where as PayPal uses a user name, password, and key. There are a number of ways to do it.
I would try creating a one-to-many table that belongs to the user, just for keys. That way a user can generate more than one hash key for different purposes. (One for reports, one for backup, one for fancy pie charts that automagically pull from Powerpoint).

Related

Spree API use on frontend

I want to use spree api on frontend to implement the ajax products search just like the one in orders/edit on backend where you enter 4 characters and it uses api to get variants.
But I am confused about the token. how can i use the following on frontend even when the user is not logged in.
/api/variants?q[product_name_or_sku_cont]=product&token=sometoken
I had a similar problem with updating cart using api (check here) but i solved that using order_token=current_order.guest_token
but here i want to implement a search and when a new user visits the site current_order is empty.
Thanks
I have change Spree::Api::Config[:requires_authentication] to false and now i am able to access it without a token

Is it possible to make a survey monkey account 'read only'

I am using the Survey Monkey api to get the url's of surveys I have created which allows me to display surveys from within my application. To do this I have to send my key and authorization with the request.
What concerns me is that Survey Monkey has an api 'create_flow' that allows surveys to be created. Using fiddler I can see my requests including the key and authorization token. As far as I can see, this means that anyone could use this information to access the api and create a new survey on my account, which I do not want.
Is there any way to stop someone from creating new surveys using the API and the auth token? I'm not really bothered about people getting access to the survey details or Uri's as all they can do is post junk survey results that only I will see, but I absolutely don't want anyone else to be able to create a survey that will be presented to all my users with potential malicious text.
It is not possible to make an account read-only.
So if I'm understanding correctly, you're shipping an application which contains your api_key and access token?
This is very much not recommended - the access token is equivalent to your account password, it gives full access to your account.
If you want a way to dynamically list your surveys, the best way to do it is create a proxy web app / API you host yourself. When someone hits that address, it uses the access token / api key you've stored on your box and grabs the list of surveys and then returns it to your app. This is the only safe way to do this.

Is this method of opening an endpoint secure? (rails)

I'm thinking through how to open an endpoint to my customer so he/she can trigger changes in their model from an external website (aka an API i think?)
I plan on creating an action in my controller where I skip authentication and authenticity token check. I would create a long random string to give to my customer so when they submit a POST request, they would include the random string in the params to confirm identity.
Is this a secure way of doing what I'm trying to do? Is there another/better way of doing this?
I just want my customer to be able to pass me values and my app take actions based on these values.
what you are talking about is usually called client token authentication.
i use it for my app as well: https://github.com/phoet/on_ruby/blob/master/app/controllers/api_controller.rb#L23-L29
my implementation uses a header-field to exchange the token.
if you want to have a more sophisticated variant you should look at oauth.
in terms of security, you might take additional measures by whitelisting ip ranges etc.
of course, use SSL connections only!

Rails API Authentication From Multiple Devices

I have a restful API that is going to accessed by multiple organizations. Their data is going to always be separate. I am using rails 4.0, emberjs, and phonegap. There are going to multiple devices accessing the API for a single organization at any point in time.
My question is how to properly design my API with these multiple organizations and devices in mind.
Current Solution:
The user must authenticate with the organization name and password. This is done over HTTPS with basic auth. After that the user is given a token that ember stores and is used for each subsequent request. Since there are multiple devices multiple API tokens can be associated with an organization. Rails uses the token to get the organization id with every request so the url /members only outputs the members related to the organization the token belows to. Thoughts on this?
Requiring every restful resource to be started with organization/id/resource seemed insecure and unwieldy to me so that is why I chose my current solution.
A Better Way?
What is a better way of doing this? Should I give each organization a subdomain and pass that back along with the token and use the token only for security and the subdomain for identifying the organization? Or should I just stick with organization/id/resource?
You are right, the token itself should not contain any "organization" part - it's insecure, as well as adding subdomain in the way you've proposed.
Instead of that you can add Organization field to the Token object (or table - depends on how you track tokens). Once you received the token you're able to get the Organization.

Building an api as a service

I am building an api for others to use. This is a simple enough Json request the user passes as some data and we pass some back.
What I would love is to secure our api and have some sort of user system where we can turn users on and off and we can log how many requests each user makes.
What would be the best way to do this in Rails? I don't want it to slow down the request. I can see ways of doing it using devise maybe but would be great to hear other people's opinions.
Thanks
Another way is to use 3scale (http://www.3scale.net) - it's free up to a traffic cap but handles all the key management, users, documentation etc. and there's a ruby library which you can drop into your code if you're using rails. (other libs are here: https://support.3scale.net/libraries).
I've done this before using the Token Authentication capabilities of devise (see https://github.com/plataformatec/devise ).
I found the following setup works:
Create a user account for each api user.
Configure devise for token authentication
Set the Token Authentication configuration to require the token to be submitted with each request.
This will allow you to enable and disable individual users as well as to track every request back to the api user that made the call.
If you're really interested in tracking usage you may want to consider also creating a database table where you track all api requests. This can be setup to belong_to the users table so that you easily find all requests from different users (e.g., #user.api_requests).
The count of all requests made by a user would be:
#user.api_requests.count
# or use a where clause to find how many of each type
#user.api_requests.where("api_request_type = ?", 'SomeAPICallType').count
One final note -- I recently used the Grape library for building out an API. I thought it was pretty well done and it worked great for our needs. I especially like the ability it provided to version APIs. Details are here: https://github.com/intridea/grape/wiki

Resources