I am creating a REST API for my next project. I am not sure what the best way to handle read / write permissions on resources is. Some resources will be readable by anyone, others will only be readable by "logged in" users, others will only be readable by specific users or admins. This also goes for write access.
How are these permissions stored and validated in REST APIs. Are there simply database tables that store the permissions for each resource or the permissions each user has to each resource? This approach seems like it could become bloated if there were many resources to keep track of not to mention every database query would require a JOIN to the table that contains permissions.
Thanks for your input in advance!
How your server side stores authentication and authorization data is entirely up to the server. It may use a database, it may use files, or none of the above.
From the perspective of RESTful HTTP, the point is that client might try to access some resource, the server may answer with 401 (Unathorized/Authentication required) or 403 (Fordbidden) HTTP error codes to enforce login/permission requirements.
Also remember, that not all services map directly to one or more relational database queries. In other words, plan to implement the authentication/authorization logic independently of the "data" if you can, and if you need fine-grained access restrictions, try to do it in code instead of joining stuff in the database, if it's possible.
Related
We are looking at integrating our apps with Openid connect for our react based apps. We have ui and relevant permissions based on user - menus, navigations etc.
Can anyone point to spec or suggest on how do we handle such permissions in relation to openid connect or oauth. Basically how do we make this permissions available to ui, one approach is dedicated API for ui permissions again authorized by access token.
Another approach is permissions in token itself. Scope is one way of holding info, but it is for delegated access. Hence we are thinking to use multivalued custom attributes for holding roles and permissions in access token. But these permissions can also be huge sometimes and thinking hence if it is good idea to keep permissions in access token.
Any valuable pointers or any design approaches for handling ui permissions list please let know, we highly appreciate it.
The most flexible option is a custom API endpoint. An access token should hold important identity values such as these:
User ID
Roles
Company ID
Tenant ID
Country Code
Subscription level
These are claims, and are populated at runtime for each user, unlike scopes, which are fixed at design time.
Access tokens are designed only to be used by APIs, and clients should never read their payload. A good practice can be to return opaque unreadable access tokens to clients, to enforce this.
The actual permissions for a role can be looked up by the API once, then cached. This is preferable to storing large payloads in access tokens.
Finally, permissions for UIs may originate from two data sources: the identity data and your business data. The API can combine a result from both data sources, and transform the result to what the UI needs. Eg which columns are visible, which are read only and so on.
I all, I'm writing a boilerplate for future projects. Composition is as follows:
Server:
Express,
Prisma 2,
Typescript,
JWT Auth (Access token in memory, Refresh in cookie)
MySQL
I'm writing an RBAC schema, and have successfully written express middlewares to determine if a user is logged in, and for if a user has a specific permission on their role.
If you've ever used any of the minecraft server permission plugins, I'm trying to emulate the common pattern used there.
Users have role(s)
Roles have permissions
Roles can inherit permissions from one or more roles
Roles have a "nextRole" field to determine what role to give when the "promote" event is triggered.
Everything works fine on the server side.
What I'm wondering about is, how should I go about copying the middlewares (login, permissions) to the client side, and how should I determine whether a user has permission to do something?
What I've looked at:
Creating a "hasPermission" endpoint wouldn't be very good as I'd need to make an API call every time a permission check is needed.
Eager loading all roles and permissions from the api when logging in and returning them in the response (I can't eager load the recursive role inheritance/nextRole as far as I know)
Returning ONLY the user without roles and permissions for the JWT/login bit and getting roles/permissions from their own endpoints (again, needs to be recursive to get all inheritance and said permissions from inheritance)
Has anyone created an RBAC schema like this, and how did you go about checking permissions on the client side without being too redundant/using too much memory/too many api calls?
This is a good question, here's my answer to it.
An app is normally protected by the auth info, which means it could be blocked if a user is not permitted. If this is a server application, it can be easily done, because the session can be used to find out the current user info including roles.
However if this is a client app, it's a bit tricky. Say we can protect a route (page or section of page) once the user log in.
if (!user.authenticated) return null
We can use the above line to block private or public user. Or other information you can grab from the user to protect more.
if (user.role !== 'Admin') return null
We could wrap in these into a component, such as
<Allow role="admin" render={...} />
I believe you get the point. However there's something which is very unique about the client approach. The entire user info is returned back, and only the user info, not the user type or permission type.
So to follow your plan, do we need to share a permission or role type to the client side? This is a million dollar question.
In practice, the UI never needs the complete info, why? because UI normally reshapes the permission a bit. That doesn't mean you can't share the complete info from the backend. Doing that may make the UI job easy or more complicated. Nobody knows.
The reason is what I explained above, the UI is writing a if statement (could be hidden) anyway. Either this if is true or false, most of the front-end code is already loaded. It's very different than the backend version, which can entirely block the deliver of the content.
I recently set up CouchDB on my server, but I'm running into a lack of information regarding changing permissions. I have an admin account, so it's not an admin party, but the restrictions are still looser than I'd like.
I'd like the Futon interface (which I've exposed) to be read-only for unauthenticated users. If I understand correctly, as it is, any visitor to the exposed Futon interface can become a member, who is
allowed to read all documents and create and modify any document except for design documents.
I'd like to take these abilities away, and configure CouchDB so that unauthenticated users can neither create documents nor become users. Basically, I want CouchDB to be read-only for everyone besides me.
Looking at the docs about security, there are ways to restrict access to the database of any kind to registered members, but I'd like to keep letting unauthenticated users have read-only access. According to this page,
If there are any member names or roles defined for a database, then only authenticated users having a matching name or role are allowed to read documents from the database (or do a GET /{db} call).
so that would restrict read access as well.
Are there any ways to fine-tune the permissions settings on CouchDB?
To simply solve your problems, assign your admin a role (eg: "ADMIN").
Then, foreach databases, restrict the "Admin" permissions to the role "ADMIN".
By default, a newly registered user won't have any role so he won't be able to access a database as an admin.
I ended up using nginx configuration to block all non-GET requests. This allows anyone to read the database, but prevents writing to the database.
However:
I can't safely expose futon now
As an admin, I can't edit the database
but to solve these
I could potentially write a new interface for CouchDB that only exposed read functionality
I can do my administration through SSH port forwarding.
If nginx blocking isn't secure, I'd love it if someone could let me know 😄
I have a Two Factor Authentication system where I need to store the Auto generated Code and the requested time in some form storage for retrieving it later purpose. I need to know what is the best way to store these sensitive information.
I was planning to use Session to store those sensitive information. When I googled, In some places people are telling its not recommended to use session to store sensitive information. Can any body explain why so.
Any suggestion to this will be highly appreciated.
Thanks
In your user database is fine, it's a web app so the database should be completely hidden from end users (if properly managed).
The rest is just making sure your actual application is secure -- ie no SQL injections, no buffer overflows, proper workflows that all pass through your server side authentication engine etc.
If you are worried about your information they should be encrypted before store them in database, for more secure propose you can use HSM (Hardware security module) to do encryption and decryption for you or even you can rely on OTP (one-time password) for two factor authentication.
What's the best practice or the common way of keeping (or not keeping) Evernote users in your application's database?
Should I create my own membership system and create a connection to Evernote accounts?
Should I store Evernote user data (or only part of it) in my own app and let the user log in only with Evernote?
Summary: you must protect their data but how you protect it is up to you. Use the integer edam_userId to identify data.
I think the API License agreement covers protection in the terms:
you agree that when using the API you will not, directly or indirectly, take or enable another to take any of the following actions:...
1.8.4 circumvent or modify any Keys or other security mechanism employed by Evernote or the API;
If you cache people's data and your server-based app lacks security to prevent people looking at other's data, then I think you're pretty clearly violating that clause. I think it's quite elegantly written!
Couple that with the responsibility clause 1.2
You are fully responsible for all activities that occur using your Keys, regardless of whether such activities are undertaken by you or a third party.
So if you don't protect someone's cached data and another user is able to get at it, you're explicitly liable.
Having cleared up the question of your obligations to (as you'd expect) protect people's data, the question is how do you store it?
Clause 4.3 covers identifiers pretty directly although it's a bit out of date now that we are all forced to use oAuth - there are no passwords ever entered into anything other a web view. However, mobile or desktop client apps must provide a mechanism for the user to log out, which must completely remove the username and password from your application and its persistent storage.
For a web app, you can't even save the username: If your Application runs as an Internet service on a multi-user server, you must not ask for, view, store or cache the sign-in name or password of Evernote user accounts.
The good news is that you can rely on the edam_userId value which comes back to you in the oAuth token credentials response, as discussed here.
When you look at the Data Model, you can see the unique id under the User and going into the User struct, see the reassuring definition The unique numeric identifier for the account, which will not change for the lifetime of the account.
Thinking about the consequences, as you can't get the user id until you have logged into the service, if you want to provide a local login for people you will have to link your local credentials to the user id. That may irk some people if they have to enter a username twice but can't be helped.
You can allow users to log-in via OAuth. Here's a guide on how that process works.
But you'll probably also want to store a minimal amount of user data, at least a unique identifier, in your database so you can do things like create relationships between the user and their notebooks and tags. Refer to the Evernote data model for those relationships. If you're using rails, this will also help you take advantage of rails conventions.