I'm wanting to make an API quickly, following REST principles - for a simple web application I've built. The first place the API will be used is to interface with an iPhone app. The API only needs handle a few basic calls, but all require authentication, nothing is public data.
login/authenticate user
get list of records in users group
get list again, only those that have changed (newly added or updated)
update record
So, following REST principles, would I setup the uri scheme?:
mysite.com/api/auth (POST?)
mysite.com/api/users (GET)
mysite.com/api/update (POST?)
and the responses will be in XML to begin with, JSON too later.
On the website, users login with email and password. Should I let them get a 'token' on their profile page to pass with every api request? (would make the stand alone '/auth' URI resource redundant).
Best practices for structuring the response xml? It seems like with REST, that you should return either 200 ok and the XML or actual proper status codes i.e. 401 etc
Any general pointers appreciated.
1- for auth, you might want to consider something like http-basic, or digest auth (note - basic in particular is insecure if not over https)
for the urls scheme:
/api/auth is not needed if you leverage basic or digest.
/api/group/groupname/ is probably more canonical
/api/update would generally be done as /api/users/username (POST) with the new data added - the resource is the user - POST is the verb
otherwise, basically your API looks sane, much depends on whether groups are hierarchical, and users must live in a group - if so, your urls should reflect that and be navigable.
2- status codes should reflect status - 200 for OK, 401 for access denied, 404 for not found, 500 for error processing. Generally you should only return an XML record if you have a good request
Authentication in an API always works by sending some authenticating token in the request header. I.e., even when using the separate /auth login approach, you would return some token, possibly a cookie, back to the user, which would need to be send together with every request.
HTTP already provides a dedicated header for this purpose though: Authorization.
The most basic HTTP "Authorization" is HTTP Basic access authentication:
Authorization : Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Digest Authentication is another, more secure, scheme. You can use this header field for any form of authentication you want though, even your custom implemented authentication.
Authorization : MyCustomAuthentication foo:bar:n293f82jn398n9r
You could send the aforementioned login token in this field. Or you could employ a request signing scheme, in which certain request fields are hashed together with the password of the user, basically sending the password without sending the password (similar to digest authentication, but you can use something better than md5). That obliterates the separate login step. AWS employs this method.
For an API in general, make good use of the HTTP status codes to indicate what is happening.
You're generally on the right track. The URI scheme should be based around the idea of resources and you should use an appropriate method to do the work.
So, GET to retrieve info. POST (Or maybe PUT) to create/change resources. DELETE for well, delete. And HEAD to check the metadata.
The structure of your XML doesn't have much to do with a RESTful API, assuming it doesn't require state management. That said, you have the right idea. If it's a good request, return the desired XML (for a GET request) and status code 200. If it's a bad request, you may also, and in some cases needed to, return something other than just the status code. Basically, get familiar with the HTTP spec and follow it as closely as possible.
Related
My api has this routes defined:
GET test.com/api/v1/users
POST test.com/api/v1/users
PUT test.com/api/v1/users/{id}
GET test.com/api/v1/users/{id}
DELETE test.com/api/v1/users/{id}
Also, i'm using OAuth2 Password authentication so these resources are only available once authenticated.
My point is.. keeping RESTFULL API principles, how should I aproach limiting PUT AND DELETE methods to the actual resource owner?
Basically I don't want anybody except the owner to be able to edit his information.
You have implemented the authentication part of your system, meaning your application knows who the users are. Now you need to devise an authorization sub-system, meaning what your users have access to.
As your question is tagged PHP and Laravel, a quick Google search for laravel authorization brings results such as this:
https://github.com/machuga/authority-l4
or
http://laravel.io/forum/02-03-2014-authority-controller-authorization-library-cancan-port
This should be a good starting point.
This is usually solved by appending a custom header, with a secret message, identifying the request as valid. I do not have any source on this I'm afraid.
Usually headers beginning with an X - discarding them from being parsed by other parties. X-Your-Secret for example.
I am currently planning the restructuring of a web application to separate the API from the application. Right now, users log in to the application by entering their operator ID (username) and password into a standard HTML form and the authentication is done by checking the database table and creating a PHP session (handled using Zend_Session). I'm not sure how to continue doing this after separating the API.
Here is some simplified code to illustrate how things currently work:
// GET https://foo.example.com/module/trips.php
if (isLoggedIn() && isAuthorized($SESSION->operatorID)) {
require 'views/trips.php';
}
// POST https://foo.example.com/module/trips.php?action=take
// ...
// this request can come from AJAX, for example
if (isLoggedIn() && isAuthorized($SESSION->operatorID)) {
$model->assignTrip($SESSION->operatorID, $_POST['trip_id']);
}
Obviously this isn't very RESTful, hence the effort to separate the two. This is what I proposed (still a work in progress):
// GET https://api.foo.example.com/v1.0/trips
echo json_encode($model->getAllTrips());
// POST https://api.foo.example.com/v1.0/trips/:trip_id/operator
$model->assignTrip($_POST['operator_id'], $trip_id);
I understand that REST is stateless. In this simplified example, only the operator should be able to assign himself/herself a trip. How do I enforce this with the API?
I've read many, many questions and articles about authentication with REST APIs and they all talk about OAuth/OAuth2 which seems great for authenticating clients of the API via tokens but nothing about authenticating users of the API client (or perhaps I'm misunderstanding something?) In my case, my API client is still the web application.
My main question: How is the API supposed to determine who the user is? Or is it even supposed to?
Alternatively I have considered doing this in the web application:
// POST https://foo.example.com/module/trips.php?action=take
// ...
// this request can come from AJAX, for example
if (isLoggedIn() && isAuthorized($SESSION->operatorID)) {
// Use cURL to send an HTTP POST request with the appropriate data to
// https://api.foo.example.com/v1.0/trips/6/operator
}
That seems like unnecessary overhead but that's what it looks like in this answer. I thought that after my restructuring I should be doing something like this from the JavaScript:
$.ajax({
type: 'POST',
url: 'https://api.foo.example.com/v1.0/trips/' + trip + '/operator',
data: {
operator_id: 6601
}
}).success(function() {
// It worked!
});
I've looked at GitHub API Authentication as an example and the Basic Usage uses curl -u "username" <api-endpoint-url>. I'm not concerned about using the Authorization HTTP header as this application is already HTTPS only but in this case wouldn't I need to store the password in the locally (e.g. Web Storage or something)?
I've also read this blog post and I'm not sure if that's what I'm supposed to be doing and if so, am I supposed to include the username and password in that hashed blob of data?
Perhaps I am misunderstanding how APIs are supposed to work in general, if so it would be great for someone to clear that up!
I agree that send some header data and store it localy are strange, but, believe, that's the way.
You can take a look to HMAC authentication.
A lot of APIs today use it, or adapt it to work with. You will ever send some user ID in header, concatenated with your hash. The server will recognize the user by that readers.
You don't need to store the password localy, just the hash (or a token) sent by server when the auth request are made.
Clearing all:
Make the API call to authenticate the user
The server will check the user login/password, if all fine it will store a TOKEN and return it on the request.
The client store the token
All the subsequent request will send that token in the header
The server will always check if that token are valid, and, find the current user using the token or another data sent in headers
I'll build a single page web app (with Backbone js) and make it consume a Restful API (in PHP) that I've to build too.
I wonder how to handle my user authentication to the API and manage the authorization when user request some data ?
I know that a restful api should be stateless but I'm stuck at this point.
Thanks
The authentication is easy.
You can handle sessions as resources:
POST /sessions {email, password}
-> {userId, token}
After that you can send back the token in a http header or in a cookie (better in http header because it protects you from CSRF attacks). I the service does not get token in the request header, than it can send back a 401 unauthorized response. If you cannot create the session, you can send back a 4** request, I use to send back 404 not found.
The authorization is harder.
You have to decide how granular you authorization system should be. It can be ACL, RBAC, ABAC, depends on how complicated your application and your access rules are. Usually people use ACL and RBAC hardcoded like this (fictive language):
#xml
role 1 editor
#/articles
ArticleController
#GET /
readAll () {
if (session.notLoggedIn())
throw 403;
if (session.hasRole("editor"))
return articleModel.readAll();
else
return articleModel.readAllByUserId(session.getUserId());
}
It works fine by simpler systems, but with this approach you will never have clean code because the access control should not be part of the business logic, you should externalize that. You can do that with an ABAC system, for example with an XACML implementation. (XACML is a great tool, but I find it a bit complicated.) You can create a custom automatic ABAC system with this approach too (same example):
#db
role 1 editor
policy 1 read every article
constraints
endpoint GET /articles
permissions
resource
projections full, owner
role 2 regular user
policy 2 read own articles
constraints
endpoint GET /articles
logged in
permissions
resource
projections owner
#/articles
ArticleController
#GET /
readAll () {
if (session.hasProjection(full))
return articleModel.readAll();
else if (session.hasProjection(owner))
return articleModel.readAllByUserId(session.getUserId());
}
I'm writing a RESTful Webservice with the Slim Microframework and use GET for reading data from a mysql database (select query) and also POST/PUT/DELETE for insert/update/delete rows in the database.
My question is now, is this not a big security issue if everybody is able to write or delete data in the database? But how could I prevent this, I thought the ST in REST stands for state transfer (so the webservice is stateless), which is a contradiction to a state like being logged in or not. And if I would pass some login data with the client which is allowed to write in the database, couldn't a bad guy catch the logindata and fake requests with it and for example delete all entries?
So, whats the normal way to go with this, the only Slim Framework examples I had found always show the route examples, but not how to secure it.
Are there also some opportunities in the Slim Framework to implement this what I need? It should be as easy as possible and the request should be responded nearly as quick as without an authentification or similar. There are no sensitive data like passwords, for me it would be enough that not everybody with a cURL commandline tool can delete all rows or things like that.
Would be great if anybody could explain me what to do and/or give some examples. I also need to know, what I maybe will need to change at the clients which are allowed to send the requests.
Lots of thanks.
Each request has to be authenticated and authorised.
People often get tied up with the word 'stateless'. This really just means that from one request to the next, the RESTful service has no prior knowledge of the users state.
BUT, the service is obviously allowed to be aware of the authenticated user that has just made a request, else how would it decide if it should allow access?
Therefore, you can 'store' the authenticated user in some variable during each request. Then it's up to you how you use this information to authorize the request.
I like to keep it simple and have all my users as a resource in my URI chain. They make requests like users/{username}/someresource.
I authenticate using http basic authentication (over SSL) and authorise based on the URI. If the request failed authentication, its a 401 Unauthorized Request. If the URI {username} and authenticated {username} do not match, the request is a 403 forbidden. If it is authenticated and authorized, the request is allowed (http code dependant on http verb)
Now that's the web service covered, now on to the web service client. This of course HAS to store state, otherwise your user would have to log in every time they make a request.
You simply store the users session in the application (as per normal session management) with the addition that you store the username and password (encrypted of course) in the session. Now every time a request is made, your web service client needs to retrieve the username and password, and send it with the request to your web service.
It will be stateless, in the sense that there won't be a session or a cookie, really. You'd normally issue out a key that would be required for INSERT/UPDATE/DELETE.
It is then up to you to pass the key with each request and to determine when a key should expire.
It would be as safe as normal http authenticated sessions. These use a cookie etc to authenticate the connected user to the stored session state.
A stateless service would be no different - the token is passed to the service just as a token is stored in a cookie for normal http. If you are worried about sniffing (IE man in the middle attacks) you would secure the link via SSL.
The authentication token generated by the service would be encrypted and would include a salt which is also verified on the server for each request. You could also limit the session time to suit your paranoia, and also check changes in source IP, user agent etc and expire the user's token if these change.
I recently ran into similar problem. As recommended by people here, I have decided to go with OAuth Authentication.
I am using HybridAuth A php wrapper for OAuth and out of the box sign in solution for Facebook, Twitter, Google, LinkedIn, etc.
I have read several tutorials to introduce myself to know more about the rest API recently. However, I have got some doubts here and there and hope someone can help me out with this.
Reading the Beginner's Guide to HTML and REST, which states:
"Resources are best thought of as nouns. For example, the following is not RESTful: 1 /clients/add This is because it uses a URL to describe an action. This is a fairly fundamental point in distinguishing RESTful from non-RESTful systems."
As such, I was wondering if for such cases where I have a user resource and to access it to do the usual insert/update/delete/retrieve
would be as follow:
www.example.com/users [get] <-- to retrieve all records
www.example.com/users/1 [get] <-- to retrieve record with id of 1
www.example.com/users/1 [put] <-- to update record with id of 1
www.example.com/user/1 [delete] <-- to delete record with id of 1
www.example.com/user [post] <-- to insert a new user record
This would have used up the 4 common verbs to make request.
What if I were to require a function such as login or perhaps in general any other types of action commands? How should the url be formed and how should the router redirect in such cases?
EDIT:
After looking at the various comments and answers. My take away from them is that the final solution would be somewhere along "use rest principles whenever possible and use the query string method with functions whenever not."
However, I was thinking of a slight variant of the implementation (not a restful implementation anymore, but following similar concepts) and wondering if it could have work out this way. Hope you guys can advice me on this.
Using the same authenticate/login function I would require to implement, could it be something along this instead:
www.example.com/users [get] <-- to retrieve all records
www.example.com/users/1 [get] <-- to retrieve record with id of 1
www.example.com/users/1 [put] <-- to update record with id of 1
www.example.com/user/1 [delete] <-- to delete record with id of 1
www.example.com/user [post] <-- to insert a new user record
as usual and if I were to require an action to be performed it will be as such:
[controller]/[action] --- user/authenticate [post] --- to login
[controller]/[id]/[action] --- user/1/authenticate [put] --- to logout
Will this work? Will there be any foreseen problems that I would face and are there similar implementations out there like this already? Please kindly advice!
REST is stateless so you need to put all the needed information into all queries. The idea is to work with the HTTP Verbs (GET, PUT, DELETE, POST - as you already descripted).
If you want an user authentification for your REST API, use something like HTTP Basic Auth, or your own Authentification. You have to send the Auth Information for every Request to the Server (stateless).
If you don't want an HTTP Basic Auth you can try some Token Authentification or any other auth.
Edit: If you want an "Check Login" Resource, build your own.
For Example GET /account/checklogin with http basic auth header informations. The Result of this Request depends on your Authinformations.
There are some actions that are hard to model in a true RESTful way - but login, for instance, can be implemented using the following pseudo code:
GET the user rights whose userID is x and password is y
if (user rights found)
assign rights to current user
else
do not assign rights to user
See this question for how to retrieve the user rights. The point in this question is that you usually need multiple ways of accessing your resources. Some are based on IDs or well-know attributes, for instance:
www.example.com/users/department [get] (get all users for a department)
www.example.com/users/roleName [get] (get all users in a particular role)
www.example.com/users/status/active [get] (get all users who are "active")
However, some ways of accessing users - especially when you need to combine two or more filtering attributes - are easier to manage using query string parameters. For instance:
www.example.com/users?department=xxx&role=yyy&status=active [get]
So, your REST API might expose a URL along the lines of:
www.example.com/users?userName=xxxx&password=yyy [get]
This URL would match the username and password parameters against the user database, and return either a 404 (if they don't match a known user), or a document representing the user, with their access rights.
Your client code then manages the current user's session - i.e. by setting the status to "logged in ", and associating the session with that user profile.
The key to making this work is assigning responsibility to the right layer - the API should not have to manage user sessions, that is the responsibility of the client application. There are cases where that doesn't work particularly well - not sure if yours is one, though.
If you really want to use a POST request, you can, of course, consider the "login" method the start of a session for that user. You could, therefore, do something like this:
www.example.com/session [POST] with parameters userID and password.
This would return a representation of the user profile and rights; it might also create documents accessible under the URLs
www.example.com/session/sessionID
www.example.com/session/user/ID/session
However, in general, it is a very dangerous idea to manage session state within the API - nearly always, you want the client session to be managed by the application interacting with the client, not by the API it talks to.
What if I were to require a function such as login or perhaps in
general any other types of action commands? How should the url be
formed and how should the router redirect in such cases?
It's not RESTful to have a login-action resource, but it is RESTful to provide a login-form resource:
/login-form
The HTML-form you return in the response functions as code-on-demand; you are supplying a configured piece of software to help the user supply their login credentials.
There would be nothing wrong with identifying the resource as just /login - I added the form-part to make the example clear.
You should avoid redirects where auth is required because it breaks the interface for clients other than web-browsers; instead you might either: provide a link to the login-form; or actually supply the login-form code in the response.
If you want to manage authentication, I prefer the approach of creating auth-tokens; in the case of Web-browsers I consider it acceptable to overload a single cookie for the purpose of helping the client supply the token with each request since they will have no other reasonable way to control the Auth header they send; obviously if you're writing your own client-application this is not a concern.
Answering your comments below, the purpose of the login form in an auth-token scenario is to create a new authentication token. So, thinking RESTfully, you model the users list of auth-tokens and POST a representation of the auth-token. This representation might contain the user's username and password. You might let the user choose their own token, or you might choose it for them and return this in the response. There is no action-URI required, and setting any cookies happens following successful creation of the new auth-token.
I recommend studying Amazon S3 REST API. It's slightly different than your requirement but its the best in-depth description of a potential REST authentication system I've seen set out:
http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAPI.html
Your thoughts on managing users RESTfully are accurate.
Hope it helps :)