Spring Authorization Server
This article is based on Spring Framework 6.
In a recent blog post on the Spring website, Steve Riesenberg announced that the Spring Authorization Server is now available on Spring Initializr. This means that developers can now easily create applications with Spring Authorization Server for OAuth2 flows.

What is Spring Authorization Server?
Spring Authorization Server is an open-source framework built on top of Spring Security that enables developers to create their own standards-based OAuth2 Authorization Server or OpenID Connect Provider. It implements many of the protocol endpoints available in the various OAuth2 and OIDC related specifications, allowing developers to focus more on their applications and users and less on flows and specifications.
Getting Started
Add the Spring Authorization Server dependency to you Maven application’s pom.xml
<!--Using Spring Boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
-- OR --
<!--Without Spring Boot-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>1.1.0</version>
</dependency>
If you’re using Gradle, add the following dependencies to the build.gradle file
implementation "org.springframework.boot:spring-boot-starter-oauth2-authorization-server"
-- OR --
implementation "org.springframework.security:spring-security-oauth2-authorization-server:1.1.0"
Add the necessary configuration in the application.properties file OR in the application.yml
application.properties
spring.security.oauth2.authorizationserver.client.client-1.registration.client-id=admin-client
# the client secret is "secret" (without quotes)
spring.security.oauth2.authorizationserver.client.client-1.registration.client-secret={bcrypt}$2a$10$jdJGhzsiIqYFpjJiYWMl/eKDOd8vdyQis2aynmFN0dgJ53XvpzzwC
spring.security.oauth2.authorizationserver.client.client-1.registration.client-authentication-methods=client_secret_basic
spring.security.oauth2.authorizationserver.client.client-1.registration.authorization-grant-types=client_credentials
spring.security.oauth2.authorizationserver.client.client-1.registration.scopes=user.read,user.write
spring.security.oauth2.authorizationserver.client.client-1.token.access-token-time-to-live=60s
#logging
logging.level.org.springframework.security=trace
application.yml
spring:
security:
oauth2:
authorizationserver:
client:
client-1:
registration:
client-id: "admin-client"
# the client secret is "secret" (without quotes)
client-secret: "{bcrypt}$2a$10$jdJGhzsiIqYFpjJiYWMl/eKDOd8vdyQis2aynmFN0dgJ53XvpzzwC"
client-authentication-methods: "client_secret_basic"
authorization-grant-types: "client_credentials"
scopes: "user.read,user.write"
Run the application with the following command
//Using maven
$ mvn spring-boot:run
//Using gradle
$ gradle bootRun

Get an access token with the following command
http -f POST :8080/oauth2/token grant_type=client_credentials scope='user.read' -a admin-client:secret

You can save the response to a TOKEN variable for introspection later
export TOKEN=eyJr...
Run the following command to inspect the token
http -f POST :8080/oauth2/introspect token=$TOKEN -a admin-client:secret

Customize the default configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig {
//A Spring Security filter chain for the Protocol Endpoints.
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
http
// Redirect to the login page when not authenticated from the
// authorization endpoint
.exceptionHandling((exceptions) -> exceptions
.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
)
)
// Accept access tokens for User Info and/or Client Registration
.oauth2ResourceServer((resourceServer) -> resourceServer
.jwt(Customizer.withDefaults()));
return http.build();
}
//A Spring Security filter chain for authentication.
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
// Form login handles the redirect to the login page from the
// authorization server filter chain
.formLogin(Customizer.withDefaults());
return http.build();
}
//An instance of UserDetailsService for retrieving users to authenticate.
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
//An instance of RegisteredClientRepository for managing clients.
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("oidc-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/oidc-client")
.postLogoutRedirectUri("http://127.0.0.1:8080/")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
return new InMemoryRegisteredClientRepository(oidcClient);
}
// An instance of com.nimbusds.jose.jwk.source.JWKSource for signing access tokens.
@Bean
public JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
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 new ImmutableJWKSet<>(jwkSet);
}
//An instance of java.security.KeyPair with keys generated on startup used to create the JWKSource above.
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
//An instance of JwtDecoder for decoding signed access tokens.
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
//An instance of JwtDecoder for decoding signed access tokens.
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
//An instance of AuthorizationServerSettings to configure Spring Authorization Server.
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
}