英文:
Spring Boot Authorization Server giving Invalid Client Error for Client Credentials grant type with client secret basic auth method
问题
当我在后端将客户端身份验证方法设置为client_secret_post并通过Postman发送以下请求时,我会收到访问令牌。
但是,当我将身份验证方法更改为client_secret_basic并通过Postman发送以下请求时,我会收到invalid_client错误。
根据我的理解,当我们将client_secret_basic作为客户端身份验证方法时,我们应该在Authorization标头中以Base64编码的格式发送clientId和clientSecret。这种理解是否正确,或者我漏掉了什么?
英文:
I have Spring Boot Authorization Server (version 1.0.1) running. When I set the client authentication method as client_secret_post at the backend and send the following request via Postman, I'm getting the access token.
Edit: I'm also attaching the screenshot of MySQL database entry for this client to show that the client_authentication_method in this case is set to client_secret_post. The client_secret here is hashed using Bcrypt Password Encoder.
However, when I change the authentication method to client_secret_basic and send the following request via Postman, I'm getting invalid_client error.
Edit: I'm also attaching the screenshot of MySQL database entry for this client to show that the client_authentication_method is set to client_secret_basic. The client_secret here is hashed using Bcrypt Password Encoder.
I'm attaching the console output of HTTP request and error response for reference here.
Here are the necessary codes and configuration snippets:
RegisteredClientRepository implementation:
@Service
public class ClientService implements RegisteredClientRepository {
private static final Logger log = LogManager.getLogger();
@Autowired
ClientRepository clientRepository;
@Override
public void save(RegisteredClient registeredClient) {
}
@Override
public RegisteredClient findById(String id) {
return this.clientRepository.findByClientId(id);
}
@Override
public RegisteredClient findByClientId(String clientId) {
return this.clientRepository.findByClientId(clientId);
}
}
Authorization Server Configuraion:
@Configuration
public class AvocadoAuthorizationServerConfiguration {
@Autowired
CryptoUtils cryptoUtils;
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
http
.apply(authorizationServerConfigurer)
.and()
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public PasswordEncoder userPasswordEncoder() {
return new BCryptPasswordEncoder(8);
}
@Bean
public JWKSource<SecurityContext> jwkSource() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
RSAPublicKey publicKey = (RSAPublicKey) cryptoUtils.getPublicKey();
RSAPrivateKey privateKey = (RSAPrivateKey) cryptoUtils.getPrivateKey();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
@Bean
public JwtDecoder jwtDecoder() {
RSAPublicKey publicKey = null;
try {
publicKey = (RSAPublicKey) cryptoUtils.getPublicKey();
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) {
e.printStackTrace();
}
return NimbusJwtDecoder.withPublicKey(publicKey).build();
}
}
As per my understanding, when we are using client_secret_basic as the client authentication method, we are supposed to send clientId and clientSecret in base64 encoded format in the Authorization header. Is this understanding correct or am I missing something?
答案1
得分: 1
如果您的RegisteredClient未将client_secret_basic作为允许的clientAuthenticationMethod,将会收到invalid_client
错误。请确保两者都已指定。例如,在使用内存客户端(仅供演示目的)时:
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("messaging-client")
.clientSecret("{noop}secret")
// **** 确保如果需要两种方法,都将它们允许
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
// ****
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.authorizationGrantType(OAuth2DeviceCode.GRANT_TYPE)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
.redirectUri("http://127.0.0.1:8080/authorized")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.scope("message.read")
.scope("message.write")
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
如果问题仍未解决,请分享您的配置。
英文:
You will get the invalid_client
error if your RegisteredClient
does not have client_secret_basic
as an allowed clientAuthenticationMethod
. Make sure you have both specified. For example, when using an in-memory client (for demonstration purposes):
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("messaging-client")
.clientSecret("{noop}secret")
// **** Ensure both are allowed if both methods are needed
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
// ****
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.authorizationGrantType(OAuth2DeviceCode.GRANT_TYPE)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
.redirectUri("http://127.0.0.1:8080/authorized")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.scope("message.read")
.scope("message.write")
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
If that does not solve your issue, please share your configuration.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论