I'd like to know if and how it is possible to set and update Keycloak (OpenID-Connect) AccessToken or IdToken attributes (so called Claims) by a client web application, after successful authentication.
The use case is to add specific user-attributes (e.g. number of pets, hair color, favorite car, etc.) to the Access- or Id-Token, while the user is logged in to our web application based on a Vue.js Frontend and a SpringBoot Backend, mainly exposing REST Services to the Frontend.
A second web-application, also using the Keycloak Token for user authentication/authorization (Single-Sign-On feature) should be able to read the user-attributes added by the first web-application to the Token.
Even I'm afraid that adding and changing of Token payload is not allowed by architectural design of OpenId-Connect, I nevertheless hope it will be possible anyhow.
Token-attributes are implemented as 'Claims' in OpenId-Connect. And Keycloak supports 'Claim' mappings during the authentication process (set by static mappings on Keycloak server as well as by code that runs on the Keycloak server).
The appropriate methods to set and get Claim key-value pairs are mentioned by the following articles:
How to create a Script Mapper in Keycloak?:
token.getOtherClaims().put("myClaimName", "claim value");
Include user locale to the Keycloak ID token:
Map<String, Object> otherClaims = token.getOtherClaims();
if (otherClaims.containsKey("myClaimName")) {
String claimValue = String.valueOf(otherClaims.get("myClaimName"));
}
For the case changing of Token payload by Keycloak clients is not allowed by architectural design, I appreciate any suggestion on best practices to hand over dynamically added user-attributes from one webapp to another webapp, having the same Keycloak Access- and/or Id-Token in common.
Yes, changing of token payload by user application is not allowed/possible by architectural design. App doesn't own private key, which is required to create proper token signature, when you change payload.
Related
I have a difficulty in understanding Spring Security and any tutorial I found was not tailored to my needs. So maybe I'll explain what I think and what I want to accomplish.
I want to create a website with Kotlin/Java backend and frontend in React. This website would need to have users with different roles (user, admin).
And (I think) the thing I need is some kind of backend that has 2 endpoints:
register (to create users in database)
login (to, based on username and password, fetch user info and role) - as some kind of token? This returned token would be then used by frontend to display specific options (i.e. do not display "ban user" for regular users) and it also would be sent to backend for checking if the person who requests for specific endpoint really should be able to call this endpoint (i.e. it should be forbidden for regular users to use "ban user" endpoint)
What should I read about, what keywords should I look into to achieve this?
For purely the Spring Boot part of the implementation, the following should do
(/register) Signup/Register endpoint taking all required parameters for your business logic. e.g Username , Password , Full Name as well the roles
(/login) For logging in , you need a token forwarded to the front end, which will then use this token in the header for the session. JWT tokens seems like what you need(sample below). For the other part of your requirement, you can keep the user object (with roles) in the session as well as check user role on the backend in the "ban user" endpoint and process accordingly.
JWT Authentication with Spring Boot
I found a good starting point in the following sample
https://github.com/bezkoder/spring-boot-spring-security-jwt-authentication
For a more complete example
https://www.bezkoder.com/spring-boot-react-jwt-auth/
Credits to
https://www.bezkoder.com/
I have come a cross Youtube Video that covers all the scenarios that your looking for and extra, with Email verification links as well. i hope this will definitely help you
Java Tutorial - Complete User Login and Registration Backend + Email Verification
I have developed a set of microservices (resource servers) using Spring Boot 1.5.x + OAuth2 with JWT. Right now each microservice is protected using Spring Security i.e. JWT access token is verified at individual resource server level. API Gateway does not have spring security in place, so it just routes the requests to appropriate server and propagates the authentication headers to downstream services.
I wanted to know if there are any disadvantages of this setup compared to the one where AccessToken is verified at API gateway level only. Or is it just a matter of opinion? Doesn't keeping security at API Gateway level breaks principle of loose coupling, because each microservice may better understand the role of a given user in its own context?
API management can do a small check on your JWT (fail early), BUT your microservices are the only one that can really manage all the security stuff !
If you set security only on api management it means that someone that can access your network will be able to push request to your API unauthenticated.
You will not be able to log who do what. And finally, if you need to set some kind of ACL, it will not be possible (When you ask to list orders, you can only list YOUR order).
Perhaps you will think of decoding your JWT on the api management layers and push a header with user name to your backend to prevent all the thing I spoke about above, but I think it is not really a good practice.
First, access to network will means I'm able to be anybody. Then JWT is much more than just a username. For instance, perhaps you use scope on your authentication layers. ( scope read orders / scope modify orders / scope delete orders). This is useful to restrict what an application can do (either at client_id level) or what a user accept to give to the application ( scope share email ...).
For this JWT on the backoffice is mandatory.
Ok you can do like username and extract data on api management and put specific headers to call backend, but really ? why do specific stuff ? oauth2 with JWT can do this for you.
Well this is an interesting question. In our team we discussed about this topic a lot. Basically you have some parameters affecting the individual answer to this question. But you should always decode and verify granted tokens on the microservice level, too. Because they contain relevant information for authentication and in some cases even for authorization. If your microservices run in a enclosed environment (e.g. on enclosed Kubernetes cluster, where only the API-Gateway is available to the outside) you could use this "mixed" solution.
You can really consider just to verify the AccessToken at the API-Gateway and let the other microservices rely on the API Gateway. The API Gateway could than exchange the AccessToken into another AuthToken, only valid in the microservice-context. This new generated AuthToken can for example contain more sensitive application-bound information, because it is not exposed to the client. The Client gets only a so called opaque token. See https://medium.com/tech-tajawal/microservice-authentication-and-authorization-solutions-e0e5e74b248a
I have a multi-tenant application (springboot keycloak adapter + spring security) secured by Keycloak. Given the multi-tenant nature of the project, I wrote a multi-client connector which works fine.
On the official Keycloak doc, it is recommended (for multi-tenant applications) to model each tenant as a new realm, but for me it works better to have multiple clients within the same same realm. This is due to following advantages:
Client scopes, groups and other configs can be shared
Users don't need to be duplicated on N different realms
SSO login works perfectly within same realm clients (by using bearer
services +CORS)
So, everything works fine except for 1 thing, my initial SSO access_token (which is then shared across all bearer-only services by means of CORS) is kind of big (it shows all the resources - tenants - and its roles within each resource/tenant).
I'd like to limit the size of the access_token, by means of using "scopes" to restrict the roles in the token to only those meaningful to the tenant where I'm logged in at that time. For this, I'm manually firing a Request to the auth server (outside of the standard functionality provided by springboot/spring security) with the goal of manually overwriting whatever access-token exists within my app, with the new one generated by my extra request.
My "new" token request looks similar to this:
SimpleKeycloakAccount currentUserAccount = (SimpleKeycloakAccount) auth.getDetails();
String authServerUrl = currentUserAccount.getKeycloakSecurityContext().getDeployment().getAuthServerBaseUrl();
String realm = currentUserAccount.getKeycloakSecurityContext().getDeployment().getRealm();
String resource = currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceName();
String refreshToken = currentUserAccount.getKeycloakSecurityContext().getRefreshToken();
String token = currentUserAccount.getKeycloakSecurityContext().getTokenString();
Http http = new Http( new Configuration(authServerUrl, realm, resource,
currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceCredentials()
, null),
(params, headers) -> {});
String url = authServerUrl + "/realms/" + realm + "/protocol/openid-connect/token";
AccessTokenResponse response = http.<AccessTokenResponse>post(url)
.authentication()
.client()
.form()
.param("grant_type", "refresh_token")
.param("refresh_token", refreshToken)
.param("client_id", resource)
.param("client_secret", "SOME_SECRET")
.param("scope", "SOME_SCOPE_TO_RESTRICT_ROLES")
.response()
.json(AccessTokenResponse.class)
.execute();
// :) - response.getToken() and response.getRefreshToken(), contain new successfully generated tokens
My question is, how can I force my-app to change/reset the standard access-token & refresh_token obtained by the usual means, with these "custom created" tokens? or is that possible at all?
Thx for any feedback!
Further Information
To clarify more, lets analyze the behavior of a typical springboot/spring security project integrated with Keycloak:
You protect your endpoints with "roles" via configurations (either on the application.properties, or on the SecurityContext)
You know that this Spring application talks in the back channel with the Keycloak authorization server, that's how you become the access_token (But all this is a black box for the developer, you only know a Principal was created, a Security Context, Credentials; etc - everything happens behind the curtains)
Considering those 2 points above, imagine that you use an Http library to basically request a new token towards the auth server token endpoint like in the code above (yes filtered by scopes and everything). So the situation now is that though you have created a valid access_token (and refresh_token); since they were created "manually" by firing a request towards the token endpoint, this new token hasn't been "incorporated" to the application because No new Principal has been created, no new security context has been generated, etc. In other words, to the springboot application this new token is non-existent.
What I'm trying to accomplish is to tell sprinboot/spring security: "Hey pal, I know you didn't generate this token yourself, but please accept it and behave as if you'd have created it".
I hope this clarifies the intent of my question.
You can revoke a token using org.springframework.security.oauth2.provider.token.ConsumerTokenServices#revokeToken method.
On the Autorization Server:
#Resource(name="tokenServices")
ConsumerTokenServices tokenServices;
#RequestMapping(method = RequestMethod.POST, value = "/tokens/revoke/{tokenId:.*}")
#ResponseBody
public String revokeToken(#PathVariable String tokenId) {
tokenServices.revokeToken(tokenId);
return tokenId;
}
Of course, you'll have to secure this method since is a very sensitive one.
In the case that each tenant is a separate client you can just use keycloak's "Scope" mapping at each client. Just turn off Full Scope Allowed and your tokens will only contain the user's roles for that specific client (tenant).
"Scope Mappings" is a a non intuitive way of saying "Define what roles should go into the access token" :-)
When turned off the UI changes and you even can configure what other roles of other clients should additionally go into the access token.
Just to give some closure to this question:
No, there doesn't seem to be any elegant or intended way to force a manual token renewal by means of using springboot/spring security keycloak connector.
The Javascript connector can do this trivially like this:
// for creating your keycloak connector
var keycloak = Keycloak({
url: 'http://localhost:8080/auth',
realm: '[YOUR_REALM]',
clientId: '[YOUR_CLIENT]'
});
// for login in (change scopes list to change access capabilities)
var options = {
scope: [EMPTY_STRING_SEPARATED_LIST_OF_SCOPES] // <-- here specify valid scopes
};
keycloak.login(options); // <-- receive a new token with correctly processed scopes
Given how easy it is to do this with the Keycloak client JS adapter, and how obscure it is to do this with the springboot/spring security adapter, it follows following:
Security design seems intended to have 2 (Keycloak security) layers; the first is a front-facing public client (usually password protected), and the 2nd layer is composed of several bearer-only services which would ussually only accept acces-tokens. If for those bearer-only services you want to implement finner grained control via scopes, you achieve that trivially by using a javascript based Keycloak client (other connectors as explained won't deal nicely with the header modification necessary to deal with OAuth2 scopes).
I was getting started with Spring Boot and Angular 7 and I came across user authentication.
Let's assume the following: I have a frontend with Angular 7 and a Backend with Spring Boot that offers API's that can be accessed via HTTP.
So I know that usually the frontend authenticates the user with e.g. JWT that stores all necessary information about the user that might be needed. But I came across the SecurityContextHoler of Spring Boot Security:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
This allows me to simply access granted Authorities and so on. So I thought about the following:
Using JWT for the frontend grants the following advantages (as far as I know):
* Users can identify when using API's
* Users may be prevented from certain UI-Elements (based on roles stored in JWT)
* Modification prevention due to checksum (invalid token afterwards)
Now I could also add a check in my Controller in the Backend that checks the SecurityContextHolder for user permission (something like a Service that checks the current context permissions vs the needed permission and returns true/false). Wouldn't that be even more save, since it is in the backend (so in my inmagination everything that runs server-sided is always a little more save than what runs client-sided)?
I can store information in the frontend (like roles and a username) to use them for the UI-based-access prevention to still have the same advantages as JWT provides, but I do not have the "effort" of implementing the JWT creation.
But obviously it is not common to do it that way (at least I never saw it), so what is the advantage of the Tokenization?
They are not mutually exclusive. You would use what you call "Tokenized Authentication", like an oAuth2 Bearer token most likely in a JWT when the Authentication is performed by a separate system from your Spring Boot backend. For example, you may be using Okta, Keycloak, Google or Facebook to authenticate the user.
At a minimum, your Spring Boot backend stores the username extracted from the JWT in the Authentication. You can get Spring Boot to extract any roles in the token and add those to Authentication::grantedAuthorites. If your backend system, has it's own set of roles in addition to what's in the token, then the backend could implement a PrincipalExtractor to load a UserDetails object for this user from the database as the Principal and merge the roles in the token with those store in the local database.
You'll probably want to security certain methods in your backend with method security annotations like #PreAuthorize(), since you shouldn't trust the front end. The method security will check permissions, like hasRole("ADMIN") or hasPermission(object, 'READ') using the Principal object in SecurityContextHolder.getContext().getAuthentication();
In the end, the token assures the backend the user accessing it is who they say they are, i.e. Authentication, but does not necessarily tell the backend what they are Authorized to do. Yes, if you control the Authentication server you can include roles in the JWT, but roles don't usually provide as fine a grained control as is required.
Independent of what level of security you implement, the token is translated into an Authorization so you can use the Spring Security framework to manage access within your backend code.
There are 3 type of token in spring security OAuth2:
1. InMemory token Store
2.JWT token store
3.JDBC token store
So now you’re talking the JWT token store. The most powerful of JWT token store is prevent the authorization server load against to the database for checking such as role,token expired so it is related database load performance. Since all the information such as: role,username, token expire ,etc include in token itself. So the authorization server or other resource sever may using the public key to verify this token itself without invoke to data store.
Hope helpful! ☺️
I would like to set up an IT solution based on the Front / Back principle.
Front side I would use a technology like React, Angular and Back side I would use a technology like java spring boot to implement controller Rest.
The front will make Rest requests on the back to retrieve data.
I would like to add a security concept to the solution by implementing the JWT standard on the back. Thus the client, knowing the secret, could request a token back and could make requests by specifying the token via the header of the request.
I found several tutorials explaining how to set up this type of solutions. In particular: https://medium.com/#nydiarra/secure-...n-e57a25806c50
In this tutorial, we assume that we define somewhere (here in a H2 database) the different users of the app and their role (admin or standard).
So the front could ask a token but it would have to indicate the user and his password and the secret defined. The back looks in the database and gives a token relative to the role defined for this user.
My question is simple. Do we have to define users and roles if we want to use JWT?
What I would have liked to do is not to inform and not to store potential users and their roles.
Simply the front requests a token with the secret without giving user and the back gives a token. Which will be used later in the header of the requests.