Information Security 6 min read

Build a Spring Authorization Server with OAuth2: Step‑by‑Step Guide

This tutorial walks through setting up Spring Authorization Server on Spring Boot 2.4.2, covering Maven dependencies, custom bean configuration, token generation, testing with curl commands, and token customization options, providing a complete example for OAuth2 authorization implementation.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
Build a Spring Authorization Server with OAuth2: Step‑by‑Step Guide

Preface

Spring Authorization Server is the Spring team's latest project to support the OAuth protocol, intended to replace the original Spring Security OAuth.

After half a year of development, version 0.1.0 has been released, initially supporting authorization code, client, refresh, and revocation features of the OAuth protocol.

This article uses Spring Boot 2.4.2 and authorization‑server 0.1.0.

Server Setup

1. Maven dependencies

<code><!--oauth2 server-->
<dependency>
  <groupId>org.springframework.security.experimental</groupId>
  <artifactId>spring-security-oauth2-authorization-server</artifactId>
  <version>0.1.0</version>
</dependency>
<!--security dependency-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
</code>

2. Initial configuration

Because the official Spring Boot starter is not yet provided, you need to configure the related @Bean manually.

This configuration is based on Spring Boot 2.4.2.

<code>@Configuration
@EnableWebSecurity
@Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthServerConfiguration {

    // Define Spring Security filter chain rules
    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(authorizeRequests ->
                authorizeRequests.anyRequest().authenticated()
        ).formLogin(withDefaults());
        return http.build();
    }

    // Create default login user "lengleng" / "123456"
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails userDetails = User.builder()
                .username("lengleng")
                .password("{noop}123456")
                .authorities("ROLE_USER")
                .build();
        return new InMemoryUserDetailsManager(userDetails);
    }

    // Create default client supporting authorization code and refresh token
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient client = RegisteredClient.withId("pig")
                .clientId("pig")
                .clientSecret("pig")
                .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
                .authorizationGrantTypes(grants -> {
                    grants.add(AuthorizationGrantType.AUTHORIZATION_CODE);
                    grants.add(AuthorizationGrantType.REFRESH_TOKEN);
                })
                .redirectUri("https://pig4cloud.com")
                .build();
        return new InMemoryRegisteredClientRepository(client);
    }

    // Specify token signing/encryption keys
    @Bean
    @SneakyThrows
    public JWKSource<SecurityContext> jwkSource() {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
    }
}
</code>

Testing

Authorization Code Flow

<code>curl --location --request GET 'http://localhost:3000/oauth2/authorize?client_id=pig&amp;client_secret=pig&amp;response_type=code&amp;redirect_uri=https://pig4cloud.com'</code>

Obtain Token

<code>curl --location --request POST 'http://localhost:3000/oauth2/token' \
--header 'Authorization: Basic cGlnOnBpZw==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code={code}' \
--data-urlencode 'redirect_uri=https://pig4cloud.com'</code>

Refresh Token

<code>curl --location --request POST 'http://localhost:3000/oauth2/token' \
--header 'Authorization: Basic cGlnOnBpZw==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token={refresh_token}'</code>

Revoke Token

Via access_token

<code>curl --location --request POST 'http://localhost:3000/oauth2/revoke' \
--header 'Authorization: Basic cGlnOnBpZw==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'token={access_token}' \
--data-urlencode 'token_type_hint=access_token'</code>

Via refresh_token

<code>curl --location --request POST 'http://localhost:3000/oauth2/revoke' \
--header 'Authorization: Basic cGlnOnBpZw==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'token={refresh_token}' \
--data-urlencode 'token_type_hint=refresh_token'</code>

Extension | Token Customization

RegisteredClient supports personalized token settings via tokenSettings().

Default configuration includes token lifetime and refresh token control.

<code>protected static Map<String, Object> defaultSettings() {
    Map<String, Object> settings = new HashMap<>();
    settings.put(ACCESS_TOKEN_TIME_TO_LIVE, Duration.ofMinutes(5));
    settings.put(REUSE_REFRESH_TOKENS, true);
    settings.put(REFRESH_TOKEN_TIME_TO_LIVE, Duration.ofMinutes(60));
    return settings;
}
</code>

Conclusion

Source code: https://github.com/lltx/auth-server-demo

Because official documentation is still incomplete, refer to The OAuth 2.0 Authorization Framework for endpoint parameters and details.

JavaSpringSpring BootsecurityOAuth2authorization-server
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.