I have a multi-tenant database with the composite key
clientId - docId
The routing looks like this
/api/controller/clientId/docId
For authentication I use a "global" username such as an email + password, sent in the http-header of every request via https. The username maps explicitly to a client and is available on the backend.
What's the way to do it properly with rest and have best security?
or
Change the routing as below and get the clientId from a database before saving a record?
/api/controller/docId
This may be an obvious question, but I'm worried about potential security issues. Or is it just a no-brainer to go with the shorter routing?
Thanks!
I think /api/controller/docId
is probably the best idea or a use a single surrogate key to represent ClientId and docId (my preference).
Unless you ever need to allow clients to view other clients resources I would hide it from the URI scheme, at worst it could be considered information leakage at best it is redundant as you have authenticated the client and know who they are anyway. It is also an overhead i.e. you still must check the client id in the url is mapped to the username and password of the request so you need to retrieve the client id on each request anyway.
If you looked at how other multi tenanted environments work e.g. Sales Force's you can see that they must infer the client via the security mechanism or are lucky enough to have a unique id for every object/resource.
An approach I have seen is to put the client identifier (usually a surrogate key of somekind, avoid exposing other users db id's!) at the root of the URL e.g. /api/{clientId}/controller/docId. In a multi tenanted environment every resource is probably/by definition unique to that client.
A reason sometimes given for this approach is that having a unique url per customer assists with caching... /api/{clientId}/controller/docId or /api/controller/{clientId}/docId
A brief note over basic authentication
Nothing wrong with your approach but consider... you could retrieve the client Id whilst validating the password and user name and add that as a claim on the IPrinciple. At least that is then available in the code without any further db look ups to find it (within the life of that request).
Going a step further... consider a two step authentication mechanism where a token is issued (following correct username and password) with the client Id actually in the token as a claim. This way, subsequent requests with the token mean you won't need to call back the the db for every request to authenticate and retrieve information. Take a look at OAuth bearer tokens http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html (be sure to sign them) or some of the other approaches...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With