Information Security 7 min read

Build an OAuth2 Authorization Server with Spring Authorization Server 0.1.0

This guide walks you through setting up Spring Authorization Server 0.1.0 on Spring Boot 2.4.2, covering Maven dependencies, bean configurations, token customization, and testing with curl commands for authorization code flow, token issuance, refresh, and revocation.

macrozheng
macrozheng
macrozheng
Build an OAuth2 Authorization Server with Spring Authorization Server 0.1.0

Introduction

Spring Authorization Server is the Spring team’s latest project for OAuth‑compatible authorization servers, intended to replace the older Spring Security OAuth.

After six months of development, version 0.1.0 is released, supporting authorization code, client, refresh, and revocation endpoints.

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 available, you need to define the required @Bean components manually.

The configuration shown is based on Spring Boot 2.4.2.

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

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

    // Default in‑memory user
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
            .username("lengleng")
            .password("{noop}123456")
            .authorities("ROLE_USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }

    // 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);
    }

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

Testing

Authorization Code Request

<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>

Token Retrieval

<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

Revoke 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>

Revoke 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>

Extended Content | Token Customization

RegisteredClient supports custom token settings via tokenSettings().

<code>RegisteredClient..tokenSettings()</code>

Default settings include token lifetime and refresh token reuse 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

Since official documentation is still incomplete, refer to the OAuth 2.0 Authorization Framework for endpoint parameters.

JavaSpringSpring BootsecurityOAuth2authorization-server
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.