Information Security 9 min read

Create a Secure OAuth2 Authorization Server with Spring Boot 3.1 & JDK 17

This guide walks through setting up Spring Authorization Server on Spring Boot 3.1 with JDK 17, covering environment setup, required dependencies, custom security filter chains, in‑memory user and client configurations, JWT signing, endpoint settings, consent service, and step‑by‑step testing of the authorization code flow.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Create a Secure OAuth2 Authorization Server with Spring Boot 3.1 & JDK 17

Introduction

Spring Authorization Server is a framework that implements OAuth 2.1, OpenID Connect 1.0 and related specifications. Built on Spring Security, it provides a lightweight, customizable foundation for creating OpenID Connect identity providers and OAuth2 authorization server products.

Environment Requirements

Version 1.1.0 of Spring Authorization Server requires JDK 17 or higher and works with Spring Boot 3.1.0. Familiarity with Spring Security (especially the shift from WebSecurityConfigurerAdapter to SecurityFilterChain since Spring Security 5.7) is assumed.

Develop the First Application

1. Add Dependency

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;
  &lt;artifactId&gt;spring-security-oauth2-authorization-server&lt;/artifactId&gt;
  &lt;version&gt;1.1.4&lt;/version&gt;
&lt;/dependency&gt;</code>

2. Custom Configuration Beans

Below are the essential beans you can customize.

Authorization Server Security Filter Chain Configures the OAuth2.1 and OIDC endpoints. <code>@Bean @Order(1) public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); // Enable OpenID Connect 1.0 http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(Customizer.withDefaults()); http.exceptionHandling((exceptions) -> exceptions.defaultAuthenticationEntryPointFor( new LoginUrlAuthenticationEntryPoint("/login"), new MediaTypeRequestMatcher(MediaType.TEXT_HTML))) .oauth2ResourceServer((resourceServer) -> resourceServer.jwt(Customizer.withDefaults())); return http.build(); }</code>

Authentication Filter Chain Handles user login similar to the old WebSecurityConfigurerAdapter . <code>@Bean @Order(2) public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()) .formLogin(Customizer.withDefaults()); return http.build(); }</code>

UserDetailsService Provides in‑memory users for authentication. <code>@Bean public UserDetailsService userDetailsService() { UserDetails user = User.withUsername("user") .password("{noop}123123") .authorities(Arrays.asList(new SimpleGrantedAuthority("p1"), new SimpleGrantedAuthority("p3"))) .roles("USER") .build(); UserDetails admin = User.withUsername("admin") .password("{noop}123123") .authorities(Arrays.asList(new SimpleGrantedAuthority("p1"), new SimpleGrantedAuthority("p2"), new SimpleGrantedAuthority("p3"))) .roles("MANAGER") .build(); return new InMemoryUserDetailsManager(user, admin); }</code>

RegisteredClientRepository Defines client registration information (in‑memory example). <code>@Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient oidcClient = RegisteredClient .withId("pack001") .clientId("123123") .clientSecret("{noop}666666") .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) .redirectUri("http://localhost:8881/index.html") .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()) .build(); return new InMemoryRegisteredClientRepository(oidcClient); }</code>

JWKSource Provides RSA keys for signing JWTs. <code>@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); } private static KeyPair generateRsaKey() { try { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(2048); return generator.generateKeyPair(); } catch (Exception ex) { throw new IllegalStateException(ex); } }</code>

JwtDecoder Decodes signed JWTs using the JWK source. <code>@Bean public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) { return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource); }</code>

AuthorizationServerSettings Configures endpoint URIs. <code>@Bean public AuthorizationServerSettings authorizationServerSettings() { return AuthorizationServerSettings.builder() .authorizationEndpoint("/oauth2/v1/authorize") .tokenEndpoint("/oauth2/v1/token") .tokenIntrospectionEndpoint("/oauth2/v1/introspect") .tokenRevocationEndpoint("/oauth2/v1/revoke") .jwkSetEndpoint("/oauth2/v1/jwks") .oidcUserInfoEndpoint("/userinfo") .build(); }</code>

OAuth2AuthorizationConsentService Handles user consent for the authorization request. <code>@Bean public OAuth2AuthorizationConsentService auth2AuthorizationConsentService() { InMemoryOAuth2AuthorizationConsentService consentService = new InMemoryOAuth2AuthorizationConsentService(); OAuth2AuthorizationConsent consent = OAuth2AuthorizationConsent .withId("pack001", "user") .authority(new SimpleGrantedAuthority("xxoo")) .build(); consentService.save(consent); return consentService; }</code>

Testing the Authorization Service

1. Open a browser and request the authorization endpoint:

<code>/oauth2/v1/authorize?client_id=123123&amp;response_type=code&amp;redirect_uri=http://localhost:8080/index.html</code>

The server redirects to the login page. Use any of the in‑memory users (e.g., user / 123123 ).

After successful login, you are redirected to the redirect_uri with a code parameter.

2. Exchange the code for a token:

<code>/oauth2/v1/token?grant_type=authorization_code&amp;code=YOUR_CODE&amp;redirect_uri=http://localhost:8080/index.html</code>

The response contains an access token (JWT).

The core classes and configuration shown above are sufficient to get a basic Spring Authorization Server up and running. Further customization can be added in subsequent articles.

JavaSpring BootsecurityOAuth2OpenID Connectauthorization-server
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

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.