Search⌘ K
AI Features

Back to the Core

Explore how to create a custom user-principal by implementing the UserDetails interface and add custom roles to JWT tokens. Understand the distinctions between password grant and authorization code grant flows within OAuth2. Gain practical knowledge on securing your application by enhancing authentication mechanisms including adding roles in tokens and managing OAuth2 requests.

Let’s create a custom user-principal

A principal is a “corporation, a program thread, an individual, or anything that can have an identity”.

The user-principal implements a Spring Security Interface that is UserDetails. We prefer using the composition pattern rather than inheritance. In fact, if we decided to use inheritance, we would have had issues with the constructors, having to import all the required parameters so that the signatures of the methods match. It’s been deprecated as an approach in more recent versions. I did try that approach as well, and it was a no-go. Therefore, we prefer to inject the user into CustomUserPrincipal and, on class instantiation, we assign our user to the user attribute of our object.

If you have IntelliJ, you can just Command(Ctrl)+Click it and read info about UserDetails. The basic idea is that when we implement an interface, it is like a contract, and we need to honor it, which means we need to provide an implementation for its methods.

As you can see in the repo related to this course, this is what a principal ...

Java
package com.simplicity.authserver.security;
import com.simplicity.authserver.persistence.domain.Privilege;
import com.simplicity.authserver.persistence.domain.Role;
import com.simplicity.authserver.persistence.domain.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
public class CustomUserPrincipal implements UserDetails {
private static final long serialVersionUID = 1L;
private final User user;
public CustomUserPrincipal(User user) {
this.user = user;
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public String getPassword() {
return user.getPassword();
}
private List<String> getPrivileges(Collection<Role> roles) {
List<String> privileges = new ArrayList<>();
List<Privilege> collection = new ArrayList<>();
for (Role role : roles) {
collection.addAll(role.getPrivileges());
}
for (Privilege item : collection) {
privileges.add(item.getName());
}
return privileges;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
final List<GrantedAuthority> authorities = new ArrayList<>();
final Collection<Role> roles = user.getRoles();
for (String privilege : getPrivileges(roles)) {
authorities.add(new SimpleGrantedAuthority(privilege));
}
return authorities;
}
public Set<String> getRoles() {
Set<String> roleNames = new LinkedHashSet<>();
final Set<Role> roles = new LinkedHashSet<>(user.getRoles());
for (Role role : roles) {
roleNames.add(role.getName());
}
return roleNames;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public User getUser() {
return user;
}
}

Add additional fields to the JWT

...