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.
Related
I want to include the oauth2 authentication flow into my application, but also provide an internal database (regular register / login) as an authentication method.
I'm not that sure how to approach that behavior, as I would love to have one single state for the authentication. I've thought about exposing the authentication using the internal database as an OAuth2 application itself, therefor token management etc can be generalized.
This would be a basic example of my thought process:
To distinguish between the multiple OAuth providers, I'd have wrapped the actual token inside a JWT, which also contains the providers name (as well as have a spam protection in my backend, instead of spamming the actual provider).
I'm not sure if it's that good to store the actual user data in a database as well - But I'd need some kind of overview of registered users for the administrators to see - and maybe block or delete.
My questions in particular:
Should the OAuth token be wrapped in a JWT for identification of the provider?
Is it bad practice to store the user data in a database as well? (If not, how much data should be stored [username, ...] and when should the data be refreshed?)
Is there anything else I should keep in mind when doing the authentication flow as it is?
I'm designing a system with REST API. REST API will be implemented using Spring Boot. The system should manage employee, product, orders information. It can be used as a standalone or as a part of some existing product ecosystem. I'm looking for some resource (book, blog, online course, etc.) to help me decide how to implement authentication and authorisation.
It's quite obvious how to do it if the system is used as a standalone product. User credentials/authorisation data can be stored in the same database next to product/employee and other data.
I'm not sure how to handle everything when the application is a part of some existing ecosystem. What if:
Someone wants to reuse existing User data store for authentication or third party service like Okta or Auth0.
Use existing data to build authorisation rules. For example authorise a person to modify product data if the person belongs to some User group.
I'm thinking about Oauth2+OIDC solution. For example Okta allows add a Claim based on Expression. User groups can be provided as Claims too. It seems Okta could be a source of both Authentication and Authorisation information. I'm not sure if it's a correct way to use Oauth2 and OIDC? What are potential pitfalls storing the authorisation data this way?
I've checked Keycloak and it seems authorisation data. can be stored there. So it's not an unusual practice to manage such a data in an authorisation server.
Maybe I should use Oauth2/OIDC for authentication only? Authorisation data (assigned roles, groups, etc.) can be stored in my application database. The application should provide means to manage the information.
I'd like to get some advice or source of information for this topic.
Thank you.
I would aim to keep OAuth data fairly small - the Authorization Server (AS) typically only needs a few fields to manage login such as Name / Email and a generated user id.
When data becomes domain specific it can become a burden to manage it in the AS, whereas in your product data it is easier to spin up custom UIs etc.
Instead the AS can reach out during token issuing to an API to include important claims in access tokens - such as roles etc. Meanwhile you don't want to expose detailed access tokens to internet clients.
The Curity web site has some good resources on patterns to meet the above requirements - here are a couple of links:
IAM Primer
Claims Best Practices
I'm using IdentityServer4 for authentication, but one of the client apps is a simple MVC site with no API access. I initially set GetClaimsFromUserInfoEndpoint to true so that we could simply use the id token on requests. Everything works fine, but due to a large number of role claims associated with our users, the id token balloons, the auth cookie gets chunked, and we run into some issues with older browsers. So, I've set GetClaimsFromUserIndoEndpoint to false and looked for another way to get the claims we need on request.
I've written a custom owin middleware that queries the user info endpoint to add claims at the beginning of the request, with basic caching, but it seems quite a bit sloppier than it should. The MVC site is set to use hybrid mode, and on the beginning of the request hits the UserInfo endpoint with an access token, caches that info, and appends it to the ClaimsPrincipal.
This achieves my goals but seems like an abuse of access tokens, and I worry it may open us up to future problems since it requires access and refreshes token management.
Is there a better-recommended pattern for keeping id tokens slim, while hydrating them on request before authorization checks take place?
Thanks very much for any advice.
I am using IdentityServer4 via ASPNET Core, and I want users to access my API both by the web browser via their identity (Implicit and Hybrid), and by clients programatically (Client Credentials). I realize all I have to do is add AddIdentityServerAuthentication and I am done. However, that only solves the authentication aspect of this problem, not the authorization.
Authorization:
With ASPNET Core, you can just use Role based auth (or PolicyServer permissions which is similar) but only if you have an identity with role claims, that does not work for client credentials. So that brings us to needing to secure by role, or policies AND by scopes. How can I do this?
You cant have multiple policies, if you do, they both must pass.
You can't have multiple auth schemes, because my call to AddIdentityServerAuthentication will have to use the same authority, so how would IdentityServer4.AccessTokenValidation/JwtBearer know which you scheme challenge you are trying to pass?
Multiple requirements could work, but you need to add extra requirements on the condition that you are dealing with a non-identity access token. How can you detect what type of token you are dealing with? Is it safe to just say "If no sub, this is client creds."
Should I scrap this design and force device code flow on my users? Look at az cli it magically opens a browser, and then you can start scripting away to your hearts content. IS4 supports this with ease, especially with verficationUrlComplete
I think I have a working POC, but I am far from happy with it. https://gist.github.com/VictorioBerra/8c333a228c55d86a7c15f7f300284634
It involves basically re-implementing the default scope claim requirement handler and policyservers permission requirement handler. But thats the only way to conditionally apply the requirement handlers based on the token type.
There are at least a couple of ways of how to go around your problem of implementing role based authentication:
You might have misunderstood the fact that a client can have role claims in the client_credentials flow.
You could even have sub claim if you implemented client_credentials_custom flow and essentially bind a client to a particular user account (think of this as a service account)
A server provides a JWT to the client during authentication. That JWT contains information which is then later used by the server. For example, JWT may contain permissions array with the list of all permissions granted to a specific user.
Is it considered bad practice, if client parses the JWT and uses the permissions information contained within it? Is it better for client to make additional call to server (GET /permissions, for example) and behave according to that response?
This will strongly depend on a lot of small details; I'll try not to forget anything, but in theory it should be fine to do so and if certain conditions are met I would not consider it a bad practice.
OAuth2 states that access tokens should be opaque to clients, but JWT is just a token format (Learn JSON Web Tokens) and it's usage in other circumstances does not imply the same rules as OAuth2.
Also note that getting the information from an additional request has the same end result with the additional overhead of one more call. There would be a slight benefit if permissions are very volatile given you could repeat the calls.
However, the important part is more focused on what you mean by the client and how would the client use that information so I'll elaborate on this.
Assumptions:
the client you mention can be deployed as browser-based application (SPA's), native application or be some server-side component acting as a client.
both the server and client are controlled by the same entity.
the client and server components can be seen as a single application, that is, for an end-user the fact there's client and server components makes no difference; they use them as a whole.
Explanation
In this situation the token issued by the server is just a way for the client to later access protected resources without requiring explicit user authentication again; it's a mechanism to maintain a session between the two components.
Given the same entity controls both the client and server, it's acceptable to treat the received token as a whitebox instead of a blackbox. The client can then interpret the information in the token and take advantage of it to provide a better experience for the end-user. However, this implies that the server will need to continue to validate the token and it's permissions accordingly; any interpretation of the data by the client is purely to provide optional functionality.
Furthermore, for clients deployed to hostile environments like it would be the case for a SPA application the decisions taken by looking into the data must only result in purely aesthetic decisions, as the user could fake the permissions data. For example, you could use it to conditionally hide/disable some user interface just so that the user wouldn't have to click it to find out it wasn't allowed to do so.
A good analogy would be Javascript based input validation in web forms; you should do it for better user experience, but the server will need to do it again because the user can bypass the Javascript validation.