How to get AdditionaInformation List From OAuth2 - spring-boot

I set an additional information by using OAuth2AccessToken enhance. I can see the additional information in the token but how can I get that list in my services class?
public final class CustomTokenEnhancer implements TokenEnhancer {
#Override
public OAuth2AccessToken enhance(
OAuth2AccessToken accessToken,
OAuth2Authentication authentication) {
Map<String, Object> additionalInfo = new HashMap<>();
List<String> companies = new ArrayList<>();
companies.add("Company 1");
companies.add("Company 2");
companies.add("Company 3");
additionalInfo.put("companies", companies);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}
I tried to get authentication from security context and cascade it to Oauth2Authentication but that object doesn't have additional information list.
SecurityContext securityContext = SecurityContextHolder.getContext();
OAuth2Authentication oauth = (OAuth2Authentication)securityContext.getAuthentication();

This is how I fetched additional info named department:
#PreAuthorize("hasAuthority('ROLE_ACCOUNTS') and #oauth2.hasScope('READ')")
#GetMapping()
public List<Account> getAll(OAuth2Authentication principal) {
OAuth2AuthenticationDetails auth2AuthenticationDetails = (OAuth2AuthenticationDetails) principal.getDetails();
Map<String, Object> details = tokenStore.readAccessToken(auth2AuthenticationDetails.getTokenValue()).getAdditionalInformation();
String department= (String) details.get("department");
return accountService.getAllAccounts(department);
}

Related

Is it possible to get refresh token using OidcUserRequest?

I am loading oidcUser from OidcUserRequest in my Oauth2UserService implementation class.
#Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
OidcUser user = delegate.loadUser(userRequest);
List<GrantedAuthority> rolesAsAuthorities = getRolesAsAuthorities(user);
CustomOidcUserDetailsImpl customUser = new CustomOidcUserDetailsImpl(user, rolesAsAuthorities);
customUser.setFullName(getFullName(user));
customUser.setTelephone(getTelephone(user));
customUser.setEmail(getEmail(user));
return customUser;
}
The problem is that i just can get OauthAccessToken and IdToken from OidcUserRequest. Are there any ways of getting Oauth2RefreshToken in my service?
I get id,access,refresh tokens if i exchange authorization code for tokens manually.
#Autowired
private OAuth2AuthorizedClientService authorizedClientService;
Authentication authentication =SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthorizedClient client = authorizedClientService
.loadAuthorizedClient(
"wso2", // client registrationId
authentication.getName());
Oauth2RefreshToken refreshToken = client.getRefreshtoken();

Implement TokenEnhancer for OAuth2 + JWT

I'm trying to implement TokenEnhancer for OAuth2 + JWT using this code:
public class CustomTokenEnhancer implements TokenEnhancer {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
final Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put("organization", authentication.getName() + " test");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}
Do you know how I can add get the user role and add it into the token payload?
You won't be able to do it using that approach, you have to implement your custom behaviour for JwtAccessTokenConverter. You can see an example in the following code:
public class CustomAccessTokenConverter extends JwtAccessTokenConverter {
private static final String AUTHORITIES = "authorities";
private static final String SCOPE = "scope";
private static final String USERNAME = "username";
private static final String ADDITIONAL_INFO = "additionalInfo";
public CustomAccessTokenConverter() {
super();
}
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
OAuth2AccessToken result = super.enhance(accessToken, authentication);
result.getAdditionalInformation().putAll(getAdditionalInformation(authentication));
return result;
}
#Override
public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
Map<String, Object> defaultInformation = (Map<String, Object>) super.convertAccessToken(token, authentication);
return this.isRefreshToken(token) ? getRefreshTokenInformation(defaultInformation)
: getAccessTokenInformation(defaultInformation);
}
/**
* Filter the data included in the JWT access token
*/
private Map<String, ?> getAccessTokenInformation(Map<String, Object> sourceInformation) {
Map<String, Object> accessTokenInformation = new HashMap<>(sourceInformation);
accessTokenInformation.keySet().removeIf(k -> asList(SCOPE).contains(k));
return accessTokenInformation;
}
/**
* Filter the data included in the JWT refresh token
*/
private Map<String, ?> getRefreshTokenInformation(Map<String, Object> sourceInformation) {
Map<String, Object> refreshTokenInformation = new HashMap<>(sourceInformation);
refreshTokenInformation.keySet().removeIf(k -> asList(AUTHORITIES, SCOPE).contains(k));
return refreshTokenInformation;
}
/**
* Include an specific section with extra information in the returned {#link OAuth2AccessToken}
*/
private Map<String, Object> getAdditionalInformation(OAuth2Authentication authentication) {
Map<String, Object> authenticationAdditionalInformation = Map.ofEntries(
entry(USERNAME, authentication.getUserAuthentication().getName()),
entry(AUTHORITIES,
authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(toSet()))
);
return Map.of(ADDITIONAL_INFO, authenticationAdditionalInformation);
}
}
You can see that code and the rest of the microservice here.
On the other hand, in the following link you will be able to see a tutorial with a complete integration with: JWT + Oauth2

#PreAuthorize returns 403

I have a following method in the controller
#GetMapping("/hello")
#PreAuthorize("hasRole('ADMIN')")
public String hello() {
return "Hello " + JWTRequestFilter.UserClaim;
}
When a user who has the ADMIN role tries to access the /hello, 403 is returned. I have enabled the following in the websecurity class.
#EnableGlobalMethodSecurity(prePostEnabled = true)
Below is the JWT token.
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzZW50aHVyYW4iLCJSb2xlcyI6WyJBRE1JTiIsIlVTRVIiXSwiZXhwIjoxNTkzMDE0NDE5LCJpYXQiOjE1OTI5Nzg0MTl9.-7lTav3Nux8WVafUBGXjOxtXcE-r0fpfjb7wM7hrg6w
Even the JWT token has the role but still i'm getting 403. Does this preauthorize annotation see the role from the JWT or does it make a DB call and check the role of a user.Even I have used the #PreAuthrize annotation but still getting the same behaviour. How to resolve this 403. Below I have attached the JWTRequestFilter class.
public class JWTRequestFilter extends OncePerRequestFilter {
#Autowired
private MyUserDetailService userDetailService;
#Autowired
private JWTUtil jwtUtil;
public static String UserClaim = "";
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if(authorizationHeader != null && authorizationHeader.startsWith("Bearer ")){
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
UserClaim = username;
}
if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails= this.userDetailService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
This is how I'm generating the JWT token and how I set the roles.
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
Set<String> Userroles = new HashSet<>();
User user = userRepository.findByUsername(userDetails.getUsername());
for(Role role:user.getRoles()){
Userroles.add(role.getName());
}
claims.put("Roles",Userroles.toArray());
return createToken(claims, userDetails.getUsername());
}
Suggested Approach to identify the issue
if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails= this.userDetailService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
String authorities = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining());
System.out.println("Authorities granted : " + authorities);
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
} else {
System.out.println("Not Valid Token);
}
} else {
System.out.println("No Token);
}
Outcome: Token was valid but authorities were not loaded
Authorities granted :
Suggested Solution
Fix the MyUserDetailService to load Authorities in userDetails
Spring adds the prefix ROLE_ to the authorities.
You can either implement a setter that appends the role prefix.
Or another much simple way to do it would be to have a separate classe that implements GrantedAuthority interface
public class UserRole implements GrantedAuthority {
private MyRole role;
#Override
public String getAuthority() {
return "ROLE_" + role.toString();
}
}
//MyRole is the enum with the different roles ADMIN,VIEWER,...

Spring Boot OAuth2 manually create new JWT token

At my Spring Boot application I have configured Spring OAuth2 server with JWT tokens.
Also I have added Spring Social configuration in order to be able authenticate users via various Social Networks like Twitter, Facebook and so on.
This is my SpringSocial config:
#Configuration
#EnableSocial
public class SocialConfig extends SocialConfigurerAdapter {
#Bean
public ProviderSignInController providerSignInController(ConnectionFactoryLocator connectionFactoryLocator, UsersConnectionRepository usersConnectionRepository) {
return new ProviderSignInController(connectionFactoryLocator, usersConnectionRepository, new SimpleSignInAdapter(authTokenServices, "client_id", userService));
}
...
}
Also, based on the folksinging answer Integrate Spring Security OAuth2 and Spring Social I have implemented SimpleSignInAdapter in order to handle successful authentication with 3rdparty Social Networks:
public class SimpleSignInAdapter implements SignInAdapter {
final static Logger logger = LoggerFactory.getLogger(SimpleSignInAdapter.class);
public static final String REDIRECT_PATH_BASE = "/#/login";
public static final String FIELD_TOKEN = "access_token";
public static final String FIELD_EXPIRATION_SECS = "expires_in";
private final AuthorizationServerTokenServices authTokenServices;
private final String localClientId;
private final UserService userService;
public SimpleSignInAdapter(AuthorizationServerTokenServices authTokenServices, String localClientId, UserService userService){
this.authTokenServices = authTokenServices;
this.localClientId = localClientId;
this.userService = userService;
}
#Override
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
UserDetails userDetails = loadUserById(Long.parseLong(userId));
OAuth2AccessToken oauth2Token = authTokenServices.createAccessToken(convertAuthentication(userDetails));
String redirectUrl = new StringBuilder(REDIRECT_PATH_BASE)
.append("?").append(FIELD_TOKEN).append("=")
.append(encode(oauth2Token.getValue()))
.append("&").append(FIELD_EXPIRATION_SECS).append("=")
.append(oauth2Token.getExpiresIn())
.toString();
return redirectUrl;
}
private OAuth2Authentication convertAuthentication(UserDetails userDetails) {
OAuth2Request request = new OAuth2Request(null, localClientId, null, true, null, null, null, null, null);
return new OAuth2Authentication(request, new UsernamePasswordAuthenticationToken(userDetails, "N/A", userDetails.getAuthorities()));
}
private String encode(String in) {
String res = in;
try {
res = UriUtils.encode(in, "UTF-8");
} catch(UnsupportedEncodingException e){
logger.error("ERROR: unsupported encoding: " + "UTF-8", e);
}
return res;
}
public UserDetails loadUserById(Long id) throws UsernameNotFoundException {
User user = userService.findUserById(id);
if (user == null) {
throw new UsernameNotFoundException("User " + id + " not found.");
}
Set<Permission> permissions = userService.getUserPermissions(user);
return new DBUserDetails(user, permissions);
}
}
Everything works fine except one thing - the following line of code produces plain OAuth2 access token:
OAuth2AccessToken oauth2Token = authTokenServices.createAccessToken(convertAuthentication(userDetails));
but I need to create JWT token instead.
How to create or convert this token to JWT based ? I suppose I can use JwtAccessTokenConverter class for this purpose but don't know how at this moment.
This worked for me, after i wanted my own Custom JWT token.
DefaultTokenServices service = new DefaultTokenServices();
service.setTokenStore(jwtAccessTokenConverter);
service.setTokenEnhancer(jwtAccessTokenConverter);
OAuth2AccessToken token = service.createAccessToken(authentication);
Autowire the jwtAccessTokenConverter
#Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
After debugging I have found a solution:
private final TokenEnhancer tokenEnhancer;
...
OAuth2Authentication authentication = convertAuthentication(userDetails);
OAuth2AccessToken accessToken = authTokenServices.createAccessToken(authentication);
accessToken = tokenEnhancer.enhance(accessToken, authentication);

How to get custom user info from OAuth2 authorization server /user endpoint

I have a resource server configured with #EnableResourceServer annotation and it refers to authorization server via user-info-uri parameter as follows:
security:
oauth2:
resource:
user-info-uri: http://localhost:9001/user
Authorization server /user endpoint returns an extension of org.springframework.security.core.userdetails.User which has e.g. an email:
{
"password":null,
"username":"myuser",
...
"email":"me#company.com"
}
Whenever some resource server endpoint is accessed Spring verifies the access token behind the scenes by calling the authorization server's /user endpoint and it actually gets back the enriched user info (which contains e.g. email info, I've verified that with Wireshark).
So the question is how do I get this custom user info without an explicit second call to the authorization server's /user endpoint. Does Spring store it somewhere locally on the resource server after authorization or what is the best way to implement this kind of user info storing if there's nothing available out of the box?
The solution is the implementation of a custom UserInfoTokenServices
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/UserInfoTokenServices.java
Just Provide your custom implementation as a Bean and it will be used instead of the default one.
Inside this UserInfoTokenServices you can build the principal like you want to.
This UserInfoTokenServices is used to extract the UserDetails out of the response of the /usersendpoint of your authorization server. As you can see in
private Object getPrincipal(Map<String, Object> map) {
for (String key : PRINCIPAL_KEYS) {
if (map.containsKey(key)) {
return map.get(key);
}
}
return "unknown";
}
Only the properties specified in PRINCIPAL_KEYS are extracted by default. And thats exactly your problem. You have to extract more than just the username or whatever your property is named. So look for more keys.
private Object getPrincipal(Map<String, Object> map) {
MyUserDetails myUserDetails = new myUserDetails();
for (String key : PRINCIPAL_KEYS) {
if (map.containsKey(key)) {
myUserDetails.setUserName(map.get(key));
}
}
if( map.containsKey("email") {
myUserDetails.setEmail(map.get("email"));
}
//and so on..
return myUserDetails;
}
Wiring:
#Autowired
private ResourceServerProperties sso;
#Bean
public ResourceServerTokenServices myUserInfoTokenServices() {
return new MyUserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
}
!!UPDATE with Spring Boot 1.4 things are getting easier!!
With Spring Boot 1.4.0 a PrincipalExtractor was introduced. This class should be implemented to extract a custom principal (see Spring Boot 1.4 Release Notes).
All the data is already in the Principal object, no second request is necessary. Return only what you need. I use the method below for Facebook login:
#RequestMapping("/sso/user")
#SuppressWarnings("unchecked")
public Map<String, String> user(Principal principal) {
if (principal != null) {
OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) principal;
Authentication authentication = oAuth2Authentication.getUserAuthentication();
Map<String, String> details = new LinkedHashMap<>();
details = (Map<String, String>) authentication.getDetails();
logger.info("details = " + details); // id, email, name, link etc.
Map<String, String> map = new LinkedHashMap<>();
map.put("email", details.get("email"));
return map;
}
return null;
}
In the Resource server you can create a CustomPrincipal Class Like this:
public class CustomPrincipal {
public CustomPrincipal(){};
private String email;
//Getters and Setters
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Implement a CustomUserInfoTokenServices like this:
public class CustomUserInfoTokenServices implements ResourceServerTokenServices {
protected final Log logger = LogFactory.getLog(getClass());
private final String userInfoEndpointUrl;
private final String clientId;
private OAuth2RestOperations restTemplate;
private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;
private AuthoritiesExtractor authoritiesExtractor = new FixedAuthoritiesExtractor();
private PrincipalExtractor principalExtractor = new CustomPrincipalExtractor();
public CustomUserInfoTokenServices(String userInfoEndpointUrl, String clientId) {
this.userInfoEndpointUrl = userInfoEndpointUrl;
this.clientId = clientId;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
public void setRestTemplate(OAuth2RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
public void setAuthoritiesExtractor(AuthoritiesExtractor authoritiesExtractor) {
Assert.notNull(authoritiesExtractor, "AuthoritiesExtractor must not be null");
this.authoritiesExtractor = authoritiesExtractor;
}
public void setPrincipalExtractor(PrincipalExtractor principalExtractor) {
Assert.notNull(principalExtractor, "PrincipalExtractor must not be null");
this.principalExtractor = principalExtractor;
}
#Override
public OAuth2Authentication loadAuthentication(String accessToken)
throws AuthenticationException, InvalidTokenException {
Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);
if (map.containsKey("error")) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("userinfo returned error: " + map.get("error"));
}
throw new InvalidTokenException(accessToken);
}
return extractAuthentication(map);
}
private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
Object principal = getPrincipal(map);
List<GrantedAuthority> authorities = this.authoritiesExtractor
.extractAuthorities(map);
OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null,
null, null, null, null);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
principal, "N/A", authorities);
token.setDetails(map);
return new OAuth2Authentication(request, token);
}
/**
* Return the principal that should be used for the token. The default implementation
* delegates to the {#link PrincipalExtractor}.
* #param map the source map
* #return the principal or {#literal "unknown"}
*/
protected Object getPrincipal(Map<String, Object> map) {
CustomPrincipal customPrincipal = new CustomPrincipal();
if( map.containsKey("principal") ) {
Map<String, Object> principalMap = (Map<String, Object>) map.get("principal");
customPrincipal.setEmail((String) principalMap.get("email"));
}
//and so on..
return customPrincipal;
/*
Object principal = this.principalExtractor.extractPrincipal(map);
return (principal == null ? "unknown" : principal);
*/
}
#Override
public OAuth2AccessToken readAccessToken(String accessToken) {
throw new UnsupportedOperationException("Not supported: read access token");
}
#SuppressWarnings({ "unchecked" })
private Map<String, Object> getMap(String path, String accessToken) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Getting user info from: " + path);
}
try {
OAuth2RestOperations restTemplate = this.restTemplate;
if (restTemplate == null) {
BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
resource.setClientId(this.clientId);
restTemplate = new OAuth2RestTemplate(resource);
}
OAuth2AccessToken existingToken = restTemplate.getOAuth2ClientContext()
.getAccessToken();
if (existingToken == null || !accessToken.equals(existingToken.getValue())) {
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(
accessToken);
token.setTokenType(this.tokenType);
restTemplate.getOAuth2ClientContext().setAccessToken(token);
}
return restTemplate.getForEntity(path, Map.class).getBody();
}
catch (Exception ex) {
this.logger.warn("Could not fetch user details: " + ex.getClass() + ", "
+ ex.getMessage());
return Collections.<String, Object>singletonMap("error",
"Could not fetch user details");
}
}
}
A Custom PrincipalExtractor:
public class CustomPrincipalExtractor implements PrincipalExtractor {
private static final String[] PRINCIPAL_KEYS = new String[] {
"user", "username", "principal",
"userid", "user_id",
"login", "id",
"name", "uuid",
"email"};
#Override
public Object extractPrincipal(Map<String, Object> map) {
for (String key : PRINCIPAL_KEYS) {
if (map.containsKey(key)) {
return map.get(key);
}
}
return null;
}
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setForcePrincipalAsString(false);
return daoAuthenticationProvider;
}
}
In your #Configuration file define a bean like this one
#Bean
public ResourceServerTokenServices myUserInfoTokenServices() {
return new CustomUserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
}
And in the Resource Server Configuration:
#Configuration
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer config) {
config.tokenServices(myUserInfoTokenServices());
}
//etc....
If everything is set correctly you can do something like this in your controller:
String userEmail = ((CustomPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getEmail();
Hope this helps.
A Map representation of the JSON object returned by the userdetails endpoint is available from the Authentication object that represents the Principal:
Map<String, Object> details = (Map<String,Object>)oauth2.getUserAuthentication().getDetails();
If you want to capture it for logging, storage or cacheing I'd recommend capturing it by implementing an ApplicationListener. For example:
#Component
public class AuthenticationSuccessListener implements ApplicationListener<AuthenticationSuccessEvent> {
private Logger log = LoggerFactory.getLogger(this.getClass());
#Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
Authentication auth = event.getAuthentication();
log.debug("Authentication class: "+auth.getClass().toString());
if(auth instanceof OAuth2Authentication){
OAuth2Authentication oauth2 = (OAuth2Authentication)auth;
#SuppressWarnings("unchecked")
Map<String, Object> details = (Map<String, Object>)oauth2.getUserAuthentication().getDetails();
log.info("User {} logged in: {}", oauth2.getName(), details);
log.info("User {} has authorities {} ", oauth2.getName(), oauth2.getAuthorities());
} else {
log.warn("User authenticated by a non OAuth2 mechanism. Class is "+auth.getClass());
}
}
}
If you specifically want to customize the extraction of the principal from the JSON or the authorities then you could implement org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor and/ org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor respectively.
Then, in a #Configuration class you would expose your implementations as beans:
#Bean
public PrincipalExtractor merckPrincipalExtractor() {
return new MyPrincipalExtractor();
}
#Bean
public AuthoritiesExtractor merckAuthoritiesExtractor() {
return new MyAuthoritiesExtractor();
}
You can use JWT tokens. You won't need datastore where all user information is stored instead you can encode additional information into the token itself. When token is decoded you app will be able to access all this information using Principal object
We retrieve it from the SecurityContextHolder's getContext method, which is static, and hence can be retrieved from anywhere.
// this is userAuthentication's principal
Map<?, ?> getUserAuthenticationFromSecurityContextHolder() {
Map<?, ?> userAuthentication = new HashMap<>();
try {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof OAuth2Authentication)) {
return userAuthentication;
}
OAuth2Authentication oauth2Authentication = (OAuth2Authentication) authentication;
Authentication userauthentication = oauth2Authentication.getUserAuthentication();
if (userauthentication == null) {
return userAuthentication;
}
Map<?, ?> details = (HashMap<?, ?>) userauthentication.getDetails(); //this effect in the new RW OAUTH2 userAuthentication
Object principal = details.containsKey("principal") ? details.get("principal") : userAuthentication; //this should be effect in the common OAUTH2 userAuthentication
if (!(principal instanceof Map)) {
return userAuthentication;
}
userAuthentication = (Map<?, ?>) principal;
} catch (Exception e) {
logger.error("Got exception while trying to obtain user info from security context.", e);
}
return userAuthentication;
}

Resources