I use k8s for scale Authorization server (2 replicas) when I get token from authorizationServer1 and check token in resource server by introspect endpoint response 401 but authorizationServer2 get Success.
How to handle it or some guide to right way for scale Authorization server
public class AuthServer {
@Autowired
private OAuthConfig authConfig;
@Autowired
PasswordEncoder passwordEncoder;
@Value("${auth.server.issuer}")
private String issuerAuth;
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
return http.build();
}
@Bean
public TokenSettings tokenSettings() {
// @formatter:off
return TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(30L))
.build();
// @formatter:on
}
@Bean
public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
RegisteredClient registeredClient = registeredClientRepository.findByClientId(authConfig.getClientId());
if (Objects.isNull(registeredClient)) {
registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId(authConfig.getClientId())
.clientSecret(passwordEncoder.encode(authConfig.getClientSecret()))
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.tokenSettings(tokenSettings())
.scope("read")
.build();
}
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
@Bean
public JWKSource<SecurityContext> jwkSource() throws Exception {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID("key-id")
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
System.out.println(jwkSet);
return new ImmutableJWKSet<>(jwkSet);
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(3072);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer(issuerAuth).build();
}
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtEncodingContextOAuth2TokenCustomizer() {
return (context -> {
Authentication authentication = context.getPrincipal();
if (authentication.getPrincipal() instanceof String) {
OAuth2AuthorizationGrantAuthenticationToken tok = (OAuth2AuthorizationGrantAuthenticationToken) context.getAuthorizationGrant();
context.getClaims().claim("merchantCenterId", tok.getAdditionalParameters().get("merchantCenterId"));
context.getClaims().claim("roleId", tok.getAdditionalParameters().get("roleId"));
context.getClaims().claim("username", tok.getAdditionalParameters().get("user_name"));
}
});
}
}
I'll just echo what Marcus said in comments, which is that you'll need to persist authorizations and authorization consent in a database such as the JDBC implementation of the OAuth2AuthorizationService and the OAuth2AuthorizationConsentService or the guide How-to: Implement core services with JPA demonstrates. Or if you choose, you can store them in a NoSQL data store like Redis, but there is not an out-of-the-box implementation for this.
Note that you should also be storing your sessions and keys in a database or NoSQL data store (such as Redis). Spring Session is great for offloading sessions to a data store and can easily be added to your Spring Boot app, but storing keys outside the JVM has not yet been demonstrated.
For this, I'd encourage you to check out Rob Winch's talk at Spring I/O from May 2023 on Enterprise Security with Spring Authorization Server. Towards the end, his talk covers plugging in a key rotation strategy and he mentions that you can easily replace the in-memory implementation from his sample repo with one backed by a database (using Spring Data JDBC or JPA for example).
These are the tips you'll need to scale your k8s-based authz server in production.