We have an application where there are lots of permissions as claims. Loading these when the user user logs in and setting them as part of the token makes the token very large.
My thinking was to find some way of load and adding claims dynamically to the token on every call (maybe from cache to speed it up).
I know openiddict offers a bunch of server events and am wondering if one of these might be a good place to put this logic.
Is there another way this can be achieved?
Our API is designed using many permissions and I don't wish to load them each time and put code inside each api to achieve this so adding claims to the principal seems logical.
Would appreciate being pointed in the right direction.
Our API is designed using many permissions and I don't wish to load them each time and put code inside each api to achieve this so adding claims to the principal seems logical.
Then what you currently have is pretty much your best option. You could also enable reference access tokens to store the actual token payloads in the DB and make the tokens returned to the clients smaller.
If you were willing to do that at the API level, you could use the claims transformation mechanism to add claims on-the-fly: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.iclaimstransformation?view=aspnetcore-5.0
Related
So I am creating some api's on Laravel using Passport (JWT).
I am having issues deciding what is the preferred method for the following:
PUT: api/users/{user_id}
PUT: api/users/me
I need the api so that the user can change his own information, but I would also like it for the api to be accessible for the Admin to change said information.
At the moment I am only using the first API and checking if the ID is the same as the one in the JWT auth or if the one requesting the api is the Admin.
But I was also thinking that maybe it was better to have them separate. The first api should only be accessible to the Admin, and I should be taking the ID from the JWT auth for the second api.
What would be the correct choice? Or is there a better choice?
I would say using this approach is better:
PUT: api/users/{user_id}
That allows anyone to consistently link to your own profile or to some other user profile in the same way. Then depending on your authentication and authorization, you can be allowed to do different operations on that resource.
There is no correct or better choice. You seem to understand the implications of using any of them so it's really up to you to choose. With the /{user_id} version you have to be extra careful not to remove proper validation rules from your code. If you used /users/me for a GET operation you would have to be careful with setting cache headers. If a browser would cache a response to users/me and then another user would request this endpoint, then you could get some other user's data. For PUT operations, though, this is not a concern.
Our system architecture is like an admin can assign permissions on the user level. we are using JWT token for authorization, previously we use roles, and roles are added in payload on sever side we check that role and allow/disallow accordingly without hitting the database. But when we add permissions in the JWT token its payload is too heavy and affects the network traffic.
So my question is what is the best practice to deal with user base permissions in JWT token.
I don't think there is a "best practice" for this as it doesn't sound advisable to store a user's permissions in a JWT, because of the following:
Since a JWT must contain all the information necessary to execute a request, if at any given time a user has permissions removed, he will continue to have them for a period of time as long as his JWT has not expired. That is, using the approach you describe, adding or removing permissions from a user is not an effect that occurs immediately, so it is necessary to develop mechanisms so that the effect of those changes is immediate. Additionally, I consider that a user's permissions can be classified as sensitive information, and it is not recommended to store sensitive information in a JWT (since anyone can see it).
If you want to continue doing that, you can assign identifiers to permissions (such as small numbers) and store those identifiers and permissions in your server's RAM (for example, using a dictionary or hash table). Finally, in the JWT you only have to store the identifiers of the permissions, thus saving as much space as possible. This way there is no need to hit the database.
You really have two options if you are using JWTs and not some sort of session-based old framework.
You store permissions in the JWT. As pointed out there are 2 main issues with this. Firstly it becomes stale, possibly quickly. Secondly this potentially bloats the JWT depending on how many permissions you have in your application. Also, for multitenant applications you now make it significantly more awkward to switch between tenants on the fly. Because now you need to reissue a token (somehow force a logout/login) whenever the user changes tenants.
You handle permissions through a network call to a server (probably the login server) which remotely handles authorization. This adds overhead but keeps things responsive. The only downside is really network traffic. It may sound like there's ways around this but there really isn't and people have accepted the large amount of added traffic.
IMO do what is the least you need. There are bandaids for JWT staleness such as short refresh timers. There are also ways to work with bloated JWTs such as strings created from enum flags. If you do not need immediate refreshing of permissions or lots of them there is nothing wrong from a practicality standpoint of putting authorization data in the JWT.
If the above does not apply, then you need to setup a network call system to handle the authorization. Ideally this is faster/leaner than http network calls.
As an example I use gRPC calls. Example working repository you can see/run is at https://github.com/Perustaja/PermissionServerDemo
I'm extremely confused on how to use a centralized IDP with both authentication and authorization. The architecture for my project was to be a single web API and one React client. I wanted to keep things structured out into microservices just to try something more modern, but I'm having major issues with the centralized identity, as many others have.
My goal is fairly simple. User logs in, selects a tenant from a list of tenants that they have access to, and then they are redirected to the client with roles and a "tid" or tenant id claim which is just the GUID of the selected company.
The Microsoft prescribed way to add identity in my scenario is IdentityServer, so I started with that. Everything was smooth sailing until I discovered the inner workings of the tokens. While some others have issues adding permissions, the authorization logic in my application is very simple and roles would suffice. While I would initially be fine with roles refreshing naturally via expiration, they must immediately update whenever my users select a different tenant to "log in" to. However, the problem is that I cannot refresh these claims when the user changes tenants without logging out. Essentially, I tried mixing authorization with authentication and hit a wall.
It seems like I have two options:
Obtain the authorization information from a separate provider, or even an endpoint on the identity server itself, like /user-info but for authorization information. This ends up adding a huge overhead, but the actual boilerplate for the server and for the client is minimal. This is similar to how the OSS version of PolicyServer does it, although I do not know how their paid implementation is. My main problem here is that both the client and resource (API) will need this information. How could I avoid N requests per interaction (where N is the number of resources/clients)?
Implement some sort of custom state and keep a store of users who need their JWTs refreshed. Check these and return some custom response to the caller, which then uses custom js client code to refresh the token on this response. This is a huge theory and, even if it is plausible, still introduces state and kind of invalidates the point of JWTs while requiring a large amount of custom code.
So, I apologize for the long post but this is really irking me. I do not NEED to use IdentityServer or JWTs, but I would like to at least have a React front-end. What options do I have for up-to-date tenancy selection and roles? Right when I was willing to give in and implement an authorization endpoint that returns fresh data, I realized I'd be calling it both at the API and client every request. Even with cached data, that's a lot of overhead just in pure http calls. Is there some alternative solution that would work here? Could I honestly just use a cookie with authorization information that is secure and updated only when necessary?
It becomes confusing when you want to use IdentityServer as-is for user authorization. Keep concerns seperated.
As commented by Dominick Baier:
Yes – we recommend to use IdentityServer for end-user authentication,
federation and API access control.
PolicyServer is our recommendation for user authorization.
Option 1 seems the recommended option. So if you decide to go for option 1:
The OSS version of the PolicyServer will suffice for handling the requests. But instead of using a json config file:
// this sets up the PolicyServer client library and policy provider
// - configuration is loaded from appsettings.json
services.AddPolicyServerClient(Configuration.GetSection("Policy"))
.AddAuthorizationPermissionPolicies();
get the information from an endpoint. Add caching to improve performance.
In order to allow centralized access, you can either create a seperate policy server or extend IdentityServer with user authorization endpoints. Use extension grants to access the user authorization endpoints, because you may want to distinguish between client and api.
The json configuration is local. The new endpoint will need it's own data store where it can read the user claims. In order to allow centralized information, add information about where the permissions can be used. Personally I use the scope to model the permissions, because both client and api know the scope.
Final step is to add admin UI or endpoints to maintain the user authorization.
I ended up using remote gRPC calls for the authorization. You can see more at https://github.com/Perustaja/PermissionServerDemo
I don't like to accept my own answer here but I think my solution and thoughts on it in the repository will be good for anyone thinking about possible solutions to handing stale JWT authorization information.
When store owner installs my app I save access tokens into database for later use. Having access tokens from store is huge security responsibility because anybody with these tokens can modify stores from any domain/address, there is no ip or domain lock.
What method could I use to make this more secure? I was thinking to save tokens offline and then upload it only when needed (in case I need to make some global updates for all stores), then delete it again. In case when merchant access app configuration within admin, I would just save it into session. Is there any better method?
Good question.
I save them in a database as well but I encode them with a separate key from the Shopify App password. That way even if someone have access to the database because of some backdoor entrance he won't be able to use them. That said if someone have access to the code he will be able to figure out how to decrypt it since he will have access to the key.
That said I make sure that each and every request is authenticated before I show any response from the server. Since I'm using NodeJS as the back-end I make sure that there are no global variables that can be accessed or modified from different stores. Everything is neatly scoped in separated functions so that the session is scoped for the current store and no other ones will be able to dirty the other store session.
In addition I make sure that there is a webhook that fires when the client uninstall his app in order to clear my database from any information regrading his store.
I know some people are using sessions for this ( online method ) but they pose other problems that I didn't like so I stuck with a database ( offline ) since that is the quicker way to access the App instead of multiply redirects in order to save the session.
As for proposals I can give you a few tips that I learn on my way while building a few basic Apps. ( I'm not an expert on the subject by any means )
don't rely on any cookies when it comes to sensible information
authenticate every request that comes from the front-end
don't trust the user and validate any input that comes from the front-end
don't over-complicate your setup, while it's good to have high security it's bad if it makes your app slow for the user and you lose customers
look to other ready to use popular solutions that can guide you to the correct path
don't get greedy with the App scopes, only request the scopes that you need for you app
remember to clean up after yourself when it's possible but don't over do it ( too many Apps modify the code of customers and break it only to prevent any way to clean it afterwards ) Example use the ScriptTag API instead of a liquid snippet using the Asset API. If you have to use the Asset API add only the parts that you know that won't break a site. Creating a variable is ok if you are using var if the site supports IE11 creating a variable using const or let is not OK or using vanilla JS is OK but using jQuery without knowing for sure that the site has it installed globally is not OK.
More insights on the matter can be seen here:
https://help.shopify.com/en/api/getting-started/authentication/oauth/api-access-modes
https://community.shopify.com/c/Shopify-APIs-SDKs/Best-way-to-store-shops-that-have-installed-my-app-and-their/m-p/402972
I have started to design a RESTful API and I'm thinking about how to handle authentication. I want to use some kind of authentication token but I can't use OAuth o similar infrastructures so I have to handle it myself.
One of the requirements for this API is that it must have good performance, enough to handle a high volume of requests before there is the need to scale; my concern is how to make on each request the time needed to verify the token (integrity, expiration, IP Address, etc...) as little as possibile.
I suppose the token should some kind of hash and not an encrypted string containing the user information because the decryption time would be to heavy.
I've read that I could store the tokens in an in-memory hashtable where the key is the token and the value is the user info needed to process the request, but how can I make this work in a clustered environment where there will be an hashtable on each "node"?
Should I put tokens on a DB table an hit the DB every time also Handling manually the retention of expired tickets?
Probably it's not that important for the question but I'm using Spring MVC for the RESTfull API.
Thanks in advance.
I solved my problem by using both an in-memory cache and a db cache. Here is a summary of my solution that may help anyone with the same task.
the user logs in and in that moment a unique key is generated and sent back to the user.
that login token (which is basically a GUID with some processing) is also store in a db table with additional info like exipiration and with the user's info and roles. the same pieces of information are also store in memory (google guava hashtable where the token is the key)
the token must be passed along with every api call in the authorization token as #ipa suggested
the server code checks if the token is in its memory cache the user info are already available otherwise (e.g. the api call is done on another node in the cluster) the token is search in the token db
once the token is found you can check expiration, roles, etc...
This grants a good level of performance and security, the token can be generated with any arbitrary algorithm even a relative slow one since you don't have to recalculate it on every api call. Also this works with a stateless service wich can be scaled up horizontally.
I assume you use https and therefore all the traffic is encrypted. I'd suggest one of the following principles.
Basic Authentication
You can add the credentials in the Authorization header of the request. This credentials are encoded with Base64 (see below). This credentials could be sent on every request and then checked with your DB. To get this faster and less IO intensive you can still use a cache. Once I implemented an API like this without a cache and was able to handle thousands of requests per second.
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Authorization Token
There are different ways to implement your idea with a token. A common one is that every API user has his own token usually called api key which never expires. Another one is that you first have to authorize (Basic Authentication) and then get a token back which expires. This one is then used as api key for a certain time.
Either way you have to decide whether to use a cache or not. I would keep it simple and go for basic authentication and check the db every time. Almost every framework has very good support for this approach because it's simple http. If this causes performance issues (I'd recommend performance tests anyway) try to add the table with your credentials to the JPA cache. If you want to implement something with expiring tokens have a look at Infinispan.
You can store token in Redis. If you are going to store it in DB, make sure you optimise server (if you are managing it) for read operations. I have couple of implementation where folks have used key value store as well. Hashtable is also good idea.