Hello everyone, in this second part we will build the auth service. This is the guy we are looking for in this guide.

The first part is available here.

We will not use those inMemory configurations, the auth service will be built on top of a MongoDB and will be able to create users, authenticate them, store their tokens/refresh tokens and revoke it if needed.

Remember that the code is available on GitHub.

Creating the Auth Service

Let’s start creating the auth-service, we will use Spring Initializr to create the maven project. Generate it like the image.

Adding annotations

Import the generated project in your favorite IDE.

Open AuthServiceApplication class to add some annotations. Start with the @EnableResourceServer annotation, it will enable a Spring Security filter that authenticates requests via an incoming OAuth2 token.

The next one is @EnableDiscoveryClient which we already know, it will enable the discovery client implementation to let our auth service register in Registry Service.

The last one is @EnableGlobalMethodSecurity which enables Spring Security global method security. Set the prePostEnabled field from the annotation to true to enable Spring Security’s pre post annotations, we will use them later.

@SpringBootApplication

@EnableResourceServer

@EnableDiscoveryClient

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class AuthServiceApplication {

public static void main(String[] args) {

SpringApplication.run(AuthServiceApplication.class, args);

}

}

Adding the application’s configuration files

Rename the application.properties file to bootstrap.yml and add the following configuration:

spring:

application:

name: auth-service

cloud:

config:

uri: http://localhost:8888

fail-fast: true

password: 1234

username: user

In the config service application, create the auth-service.yml file to hold the configuration for auth service.

spring:

data:

mongodb:

host: localhost

port: 27017

username: oauth-user

password: password

database: oauth-db server:

servlet:

context-path: /uaa

port: 8081

If you don’t know why these files are being created, I recommend you to read this article’s first part.

Creating the domain entities and its DAO

Let’s start creating the authorities enum.

import org.springframework.security.core.GrantedAuthority;



public enum Authorities implements GrantedAuthority {

ROLE_USER;



@Override

public String getAuthority() {

return name();

}

}

This enum is responsible to define the authorities of our auth service and it implements the GrantedAuthority interface which represents an authority granted to an Authentication object.

Now create the User entity to represent our user.

@Document

public class User implements UserDetails {

@Id

private String id;



@Indexed(unique = true)

private String username;



private String password;



private boolean activated;



private String activationKey;



private String resetPasswordKey;



private Set<Authorities> authorities = new HashSet<>(); ...getters and setters

}

I omitted the getters and setters for the sake of simplicity, but you can check them here. The User class implements the UserDetails interface who provides core user information to be encapsulated into Authentication objects. The @Document , @Id and @Indexed annotations are used by Mongo, I’ll not enter in details here, but you can ask in the comments section.

Create the UserRepository to be our DAO.

import com.marcusdacoregio.authservice.domain.User;

import org.springframework.data.mongodb.repository.MongoRepository;

import org.springframework.stereotype.Repository;



import java.util.Optional;



@Repository

public interface UserRepository extends MongoRepository<User, String> {

Optional<User> findByUsername(String username);

}

And now our custom implementation of the UserDetailsService , it is a core interface which loads user-specific data. It is used throughout the spring framework as a user DAO and is the strategy used by the DaoAuthenticationProvider. You can read more about it in the official documentation.

@Service

public class CustomUserDetailsService implements UserDetailsService {



private final UserRepository userRepository;



public CustomUserDetailsService(UserRepository userRepository) {

this.userRepository = userRepository;

}



@Override

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

return userRepository.findByUsername(username)

.orElseThrow(() -> new UsernameNotFoundException("Username " + username + " not found"));

}



}

Ok, until here we created some needed classes to deal with our users.

Now we will create the classes to deal with our clients, which are the resource servers whose wants to use the authentication. Let’s start the class who represents the detail of an authorization client.

@Document

public class AuthClientDetails implements ClientDetails {

private static final long serialVersionUID = 1L;



@Id

private String id;



private String clientId;



private String clientSecret;



private String grantTypes;



private String scopes;



private String resources;



private String redirectUris;



private Integer accessTokenValidity;



private Integer refreshTokenValidity;



private String additionalInformation; ...getters and setters

}

You can check the details for the getters and setters from this class here. It’d be nice to check out the documentation for ClientDetails .

The next class is AuthClientRepository to be our DAO for AuthClientDetails .

@Repository

public interface AuthClientRepository extends MongoRepository<AuthClientDetails, String> { Optional<AuthClientDetails> findByClientId(String clientId); }

Now the class AuthClientDetailsService , it implements the ClientDetailsService which is a service interface to provide the details about an OAuth2 client.

@Service

public class AuthClientDetailsService implements ClientDetailsService {

private final AuthClientRepository authClientRepository;



public AuthClientDetailsService(AuthClientRepository authClientRepository) {

this.authClientRepository = authClientRepository;

}



@Override

public ClientDetails loadClientByClientId(String clientId) {

return authClientRepository.findByClientId(clientId).orElseThrow(IllegalArgumentException::new);

}

}

In the next section, we will start to configure security and OAuth2 in Spring.