'Spring boot auth server client/ resource server: OAuth 2.1 Authorization Code Grant programatic simulation? Password grant no longer exists

Spring Authorization Server OAuth 2.1.

How can i programatically simulate the authorization_code grant?

Since all grants except for authorization_code and client_credentials have been dropped this has become quite a headache.

The scenario calls for a @Scheduled job to login as a specific user where the client credentials are encoded properties within the server performing the login. The user roles are important when executing downstream resources and is considered a regular user of the registered Client.

Using the Password grant was perfect for this scenario in OAuth 2.0.

Before i start hacking our Spring Auth server and implement a Password grant for registered resources or maybe overloading the client_credentials for user_credentialed payloads.

Quite a pain if you ask me, so please enlighten me? Are there any patterns for implementing this that i have not yet discovered?



Solution 1:[1]

While I'm curious what specific use case you have that needs to perform tasks as a particular user (as opposed to a single confidential client), it should still be possible with customization.

maybe overloading the client_credentials for user_credentialed payloads

This approach makes the most sense to me as a way to adapt supported flows in OAuth 2.1 to emulate a deprecated flow like the resource owner password grant. You can use a variation of this github gist, extending it with your user's authorities if needed. One possible solution might look like the following:

@Component
public final class DaoRegisteredClientRepository implements RegisteredClientRepository {
    private final RegisteredClient registeredClient;
    private final UserDetailsService userDetailsService;

    public DaoRegisteredClientRepository(RegisteredClient registeredClient, UserDetailsService userDetailsService) {
        this.registeredClient = registeredClient;
        this.userDetailsService = userDetailsService;
    }

    @Override
    public void save(RegisteredClient registeredClient) {
        throw new UnsupportedOperationException();
    }

    @Override
    public RegisteredClient findById(String id) {
        return this.registeredClient.getId().equals(id) ? this.registeredClient : null;
    }

    @Override
    public RegisteredClient findByClientId(String clientId) {
        UserDetails userDetails;
        try {
            userDetails = this.userDetailsService.loadUserByUsername(clientId);
        } catch (UsernameNotFoundException ignored) {
            return null;
        }

        return RegisteredClient.from(this.registeredClient)
                .clientId(userDetails.getUsername())
                .clientSecret(userDetails.getPassword())
                .clientSettings(ClientSettings.builder().setting("user.authorities", userDetails.getAuthorities()).build())
                .build();
    }
}

This uses a single client registration, but makes use of a UserDetailsService to resolve a subject representing your user's username and a secret which is actually the user's password. You would then need to provide an @Bean of type OAuth2TokenCustomizer<JwtEncodingContext> to access the user.authorities setting and add those authorities to the resulting access token (JWT) using whatever claim your resource server expects them in.

Alternatively, you could just override the scopes parameter of the returned RegisteredClient if desired.

Solution 2:[2]

I had the similar problem and ended up creating a password grant emulation servlet filter. Please refer to my example: https://github.com/andreygrigoriev/spring_authorization_server_password_grant

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Steve Riesenberg
Solution 2 Andrey Grigoriev