What is the correct way to authorize and structure a RESTful backend

Many examples of RESTful web services do not address the problems that many applications today are multi-tenant.

Imagine a multi-user backend that provides a RESTful API . The backend data architecture uses a common database and a common schema. Each table will contain a link to tenant_id :

 +-------------+----+-----------------+ | tenant_name| id | shared_secret | +-------------+----+-----------------+ | bob | 1 | 2737sm45sx543 | +-------------+----+-----------------+ | alice | 2 | 2190sl39sa8da | +-------------+----+-----------------+ +-------------+----+-------+-----------+ | pet_name | id | type | tenant_id | +-------------+----+-------+-----------+ | fuffy | 1 | dog | 1 | +-------------+----+-------+-----------+ | kerry | 2 | cat | 2 | +-------------+----+-------+-----------+ 

Question 1 : With three or more client applications (e.g. Android, iOS, and a web application) that interact with the RESTful backend , how would you authenticate against the backend?

 RESTful backend, API, HTTP-Verbs, shared database and schema | | +---- Web Application (Client 1) | | | + Alice | | | + Bob | +---- Android Application (Client 2) | | | + Alice | | | + Bob | +---- iOS Application (Client 3) | | | + Alice | | | + Bob | 

Each client must allow Alice and Bob to manage their pets. Each client is a graphical interface, and it will use (internally, making HTTP requests) a backend. Question: how can each client authenticate to the backend?

Suppose HMAC (it is excellent RESTful, no sessions): this method involves signing the payload with a shared secret (never sent over the wire). Should each client have its own copy of the tenant table (which contains the shared_secret field)?

 Android App -> Client Sign -> Signed Request -> Backend -> Result Web App -> Client Sign -> Signed Request -> Backend -> Result 

Question 2 : what does the resource URI look like?

Here are two possibilities for the ways to GET Bob:

Opportunity # 1: The Authorization header gives you the tenant's name (unique):

 GET /pets HTTP/1.1 Host: www.example.org Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz 

Opportunity number 2. tenant_id sent as a request parameter:

 GET /pets/tenant_id=1 HTTP/1.1 Host: www.example.org Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz 
+7
source share
4 answers

Part 1

(Thinking out loud: Have you decided to use HTTP and HMAC? If so, why are you asking us?)

I would suggest HTTPS with Basic Auth. Just. This is enough for Stripe after all.

Literature:

Refresh . The following is additional information on how to handle auth:

  • Each client application will contact the service using an API key. Using HTTPS and Basic Auth, the client will provide the API key as the primary username. He does not need to specify a password, since he uses HTTPS. You need to assign an API key for each application (web application, Android, iOS), I see two ways:

    but. One option is to provide each user with one API key that is shared by clients.

    B. Another option is to provide each client with a unique application.)

  • But how do you get customer keys in the first place? Create the key request API request endpoint. I suggest giving each client a starter key, which is used only to communicate with this endpoint. (The starter key does not provide another access.) When the user first uses the client, he / she must authenticate. The client transmits this along with the key request endpoint so that it can generate a key associated with the user. From now on, each client has an API key associated with the client.

Part 2

Consider providing each tenant with a subdomain. If you use Rails (or perhaps any modern web stack), you can use the subdomain to find the tenant ID. Then your API can be used as follows:

 GET http://tenant1.app.co/pets GET http://tenant2.app.co/pets GET http://tenant3.app.co/pets 

Links (specific to Rails, but should be useful via network stacks):

Note. As your example shows, for simplicity I will not reuse the same identifier for different tenants. For example, the following simple way:

 GET http://tenant1.app.co/pets/200 GET http://tenant2.app.co/pets/201 GET http://tenant3.app.co/pets/202 

The approach I am describing is much cleaner than passing tenant_id as a request parameter. Also, using tenant_id as a parameter seems wrong. I like to use parameters for more “algorithmic” things, as I read in Ruby and Richardson's “RESTful Web Services”.

Literature:

+4
source

By "multi-tenant" do you just mean users of applications / web services? Multi-tenant can often mean something more complicated msdn.microsoft.com/en-us/library/aa479086.aspx .

You need to authenticate each user using a web service. This can be done using basic HTTP authentication over SSL.

In terms of web services, you authenticate the same way for all three clients. The service does not care about the type of client - this is the point. Perhaps you need different views for your customers, for example. XHTML or JSON. I like to keep things simple and always choose JSON.

For resources, the easiest way to manage them is to have a user resource as a top level, and then combine all the resources for each user, for example.

 GET users/fred/pets - returns all pets for user fred GET users/fred/pets/sparky - returns details on freds pet sparky 

The great thing about this is that you can add a code to authorize each request, for example. You can have two users, fred and jack. Both users will be authenticated, but you should only allow fred to request its resources and socket to request it. You just need to add authorization checks in api, for example. get the username from the URI, get the username of the authenticated user, verify that they are the same. If you do not return something like http 403 is prohibited, if they are the same, allow the request.

I think if you are still unclear, you need to read the details of REST. By far, the best book on this topic is RESTful Web Services . It covers REST from first principles. It also has a very good section on resource development and user management and multiple clients.

+3
source

I am not sure to understand this question, since in this case the multi-user activity seems a little redundant. However, I can try to answer the second question.

REST is a "resource" architecture, and you should understand that /pets and /pets/?tenant=1 do not refer to the same resource:

  • /pets refers to the pets of the current user,
  • /pets/?tenant=1 refers to Bob's animals.

Although no solution is wrong, it is usually best to get a second solution. The URIs are really meant to be shared, and you have more reasons to share “Bob's pets” (even if authentication and authorization are required for this) than the abstract “my pets” that will be different for each user.

See If Resource Identifiers Are Present in URLs? for a similar discussion ...

+1
source

If the HTTP protocol is a protocol that uses all 3 types of client, you only need to implement one authentication scheme . You can choose your poison - Basic , Digest , Oauth2 or Cookie - some of the methods used. Since this is over HTTP, I see no reason to replicate this logic. There are probably a few frameworks that will abstract this for you depending on your platform.

To distinguish the type of client, you can use the HTTP header . user-agent can make this possible. Another option is to use a custom header that you define. Any HTTP client is able to set headers, and any server can handle a custom header. A decent web structure will make them available to you with relative ease. I believe that as an auxiliary service, you will handle all client requests evenly - or as much as possible. Of course, supporting one backend is preferable to three .

How much your API should look like is entirely up to you. To stay RESTful, how to get a cup of coffee is worth reading the mandatory reading link - insert Roy Fielding into Thesis . Most likely, what you are really looking for is a guide to writing "resourceful" links.

From the list you list, you prefer the second one, /pets?userId=bob , if users may need access to all the pets in the system. Prefer the first one, /pets , if the user only ever needs access to their pets.

+1
source

All Articles