Build an OAuth2 Authorization Server with Spring Authorization Server 0.2.0
This tutorial walks through setting up Spring Authorization Server 0.2.0 on Spring Boot 2.5.3, covering required dependencies, security configuration, SAS server setup, testing the authorization code flow, token exchange, refresh, and revocation, with complete code snippets and curl commands.
Background
Spring Authorization Server (SAS) is the Spring team's latest OAuth‑compatible authorization server project, intended to replace the original Spring Security OAuth Server.
After six months of development, version 0.2.0 has been released, supporting authorization code, client, refresh, revocation and other OAuth features.
The SAS project has moved to the official repository and is now an official sub‑project.
The author's earlier article is no longer compatible with the current version, so this guide consolidates the setup steps.
Environment: Spring Boot 2.5.3 && SAS 0.2.0.
Getting Started
1. Core Dependencies
Include SAS and Spring Security dependencies (see comments in the pom snippet).
<code><!-- Note: the official repository does not have the 'experimental' groupId; be careful or the jar cannot be downloaded -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.0</version>
</dependency>
<!-- Provide form authentication -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</code>2. Configure Spring Security
Define the user source and form‑login details.
<code>@EnableWebSecurity
public class DefaultSecurityConfig {
@Bean
UserDetailsService users() {
UserDetails user = User.builder()
.username("lengleng")
.password("{noop}123456")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
).formLogin(withDefaults());
return http.build();
}
}
</code>3. Configure SAS Server
<code>@Configuration
@EnableWebSecurity
public class AuthServerConfiguration {
// security mounts SAS – the most important step
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.formLogin(Customizer.withDefaults()).build();
}
// client registration
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient client = RegisteredClient.withId("pig")
.clientId("pig")
.clientSecret("{noop}pig")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantTypes(authorizationGrantTypes -> {
authorizationGrantTypes.add(AuthorizationGrantType.AUTHORIZATION_CODE);
authorizationGrantTypes.add(AuthorizationGrantType.REFRESH_TOKEN);
})
.redirectUri("https://pig4cloud.com")
.build();
return new InMemoryRegisteredClientRepository(client);
}
// beans for JWT generation (see source for details)
@Bean
@SneakyThrows
public JWKSource<SecurityContext> jwkSource() {
// ...
}
@Bean
public static JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
// ...
}
}
</code>Test Run
With the above configuration the SAS server is ready. The following steps test the authorization‑code flow.
Open the browser and navigate to:
<code>http://localhost:3000/oauth2/authorize?client_id=pig&client_secret=pig&response_type=code&redirect_uri=https://pig4cloud.com</code>After logging in, the server redirects back with an authorization code.
Exchange the code for a 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=YOUR_AUTH_CODE' \
--data-urlencode 'redirect_uri=https://pig4cloud.com'</code>Refresh the 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=YOUR_REFRESH_TOKEN' \
--data-urlencode 'redirect_uri=https://pig4cloud.com'</code>Revoke Tokens
Revoke using an 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 using a 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>Next Preview
SAS implements OAuth 2.1 and does not support the password grant type. The next article will show how to extend SAS to add password‑grant support. Stay tuned.
Source code: https://github.com/lltx/auth-server-demo
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.