Spring Boot oauth2 with local user database

Viewed 1210

I have implemented OIDC authentication in my Spring Boot web application by adding the spring-boot-starter-oauth2-client dependency and configuring OAuth2 client settings in application.properties.

In the Spring Boot and OAuth2 guide there is a section "How to Add a Local User Database":

How to Add a Local User Database

Many applications need to hold data about their users locally, even if authentication is delegated to an external provider. We don’t show the code here, but it is easy to do in two steps.

  1. Choose a backend for your database, and set up some repositories (using Spring Data, say) for a custom User object that suits your needs and can be populated, fully or partially, from external authentication.

  2. Implement and expose OAuth2UserService to call the Authorization Server as well as your database. Your implementation can delegate to the default implementation, which will do the heavy lifting of calling the Authorization Server. Your implementation should return something that extends your custom User object and implements OAuth2User.

Hint: add a field in the User object to link to a unique identifier in the external provider (not the user’s name, but something that’s unique to the account in the external provider).

I have searched a bit but I have not found a code example for the scenario described in the excerpt.

What is the best way to implement the scenario above?

I guess the main parts would be:

  • On OIDC login, automatically create a user in the database if it does not exist
  • The web application controller methods have access to the database object that represents the logged-in user

Update:

The guide has a github issue comment that suggests to look at the custom-error sample from the guide's source code. I guess the first part (on OIDC login, automatically create a user if one does not exist) can be done after the call to DefaultOAuth2UserService().loadUser(request). But what about the second part - how can my custom db-backed-user-object be made available to my web application's controller methods?

@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService(WebClient rest) {
    DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
    return request -> {
        OAuth2User user = delegate.loadUser(request);
        if (!"github".equals(request.getClientRegistration().getRegistrationId())) {
            return user;
        }

        OAuth2AuthorizedClient client = new OAuth2AuthorizedClient
                (request.getClientRegistration(), user.getName(), request.getAccessToken());
        String url = user.getAttribute("organizations_url");
        List<Map<String, Object>> orgs = rest
                .get().uri(url)
                .attributes(oauth2AuthorizedClient(client))
                .retrieve()
                .bodyToMono(List.class)
                .block();

        if (orgs.stream().anyMatch(org -> "spring-projects".equals(org.get("login")))) {
            return user;
        }

        throw new OAuth2AuthenticationException(new OAuth2Error("invalid_token", "Not in Spring Team", ""));
    };
}
0 Answers
Related