You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Authorization Server配置正确仍报invalid_client错误排查

问题分析:Spring Authorization Server 返回 invalid_client 错误

问题场景

搭建Spring Authorization Server(Spring Boot 3.4.1)时,使用预配置客户端请求访问令牌,始终收到invalid_client错误。

配置代码

RegisteredClientRepository 配置

@Bean  
fun registeredClientRepository(): RegisteredClientRepository {  
    val adminClient = RegisteredClient.withId("admin-client")  
        .clientId("admin-client")  
        .clientSecret("{noop}secret")
        .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)  
        .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)  
        .scope("client.create")  
        .build()  
    return InMemoryRegisteredClientRepository(adminClient)  
}  

授权服务器安全过滤器链配置

@Bean
@Order(1)
@Throws(Exception::class)
fun authorizationServerSecurityFilterChain(
    http: HttpSecurity, jdbcOperations: JdbcOperations, registeredClientRepository: RegisteredClientRepository
): SecurityFilterChain {
    val authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer()
    http.authorizeHttpRequests { it.requestMatchers("/auth/**").permitAll() }
        .securityMatcher(authorizationServerConfigurer.endpointsMatcher).with(
        authorizationServerConfigurer
    ) { authorizationServer ->
        authorizationServer.registeredClientRepository(registeredClientRepository(jdbcOperations))
            .authorizationService(JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository))
            .authorizationConsentService(
                JdbcOAuth2AuthorizationConsentService(
                    jdbcOperations,
                    registeredClientRepository
                )
            ).authorizationServerSettings(endpoints).tokenGenerator(JwtGenerator(NimbusJwtEncoder(jwkSource())))
    }
    return http.build()
}

请求信息

POST /auth/oauth2/token  
Content-Type: application/x-www-form-urlencoded  
Authorization: Basic YWRtaW4tY2xpZW50OnNlY3JldA==  # Base64("admin-client:secret")  

grant_type=client_credentials&scope=client.create  

已确认信息

  • 客户端admin-client已存在于数据库,密钥为明文secret
  • 尝试了CLIENT_SECRET_BASIC(请求头)和CLIENT_SECRET_POST(请求体)两种认证方式,均返回相同错误
  • 令牌端点URL与AuthorizationServerSettings配置一致

错误响应

{  
  "error": "invalid_client"
}  

核心疑问

为何Spring Authorization Server会拒绝合法客户端凭证?客户端密钥存储或认证方法验证是否存在隐藏要求?


解决方案

1. 修复RegisteredClientRepository的注入问题

你的过滤器链配置存在核心错误:在authorizationServer.registeredClientRepository中,你调用了registeredClientRepository(jdbcOperations),这会创建一个全新的内存版客户端仓库,而非注入你预先定义的RegisteredClientRepository Bean。这意味着授权服务器实际使用的是一个空的客户端仓库,自然找不到admin-client。

修正代码,直接使用注入的参数:

@Bean
@Order(1)
@Throws(Exception::class)
fun authorizationServerSecurityFilterChain(
    http: HttpSecurity, jdbcOperations: JdbcOperations, registeredClientRepository: RegisteredClientRepository
): SecurityFilterChain {
    val authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer()
    http.authorizeHttpRequests { it.requestMatchers("/auth/**").permitAll() }
        .securityMatcher(authorizationServerConfigurer.endpointsMatcher).with(
        authorizationServerConfigurer
    ) { authorizationServer ->
        // 直接使用注入的registeredClientRepository,不要重新调用方法创建实例
        authorizationServer.registeredClientRepository(registeredClientRepository)
            .authorizationService(JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository))
            .authorizationConsentService(
                JdbcOAuth2AuthorizationConsentService(
                    jdbcOperations,
                    registeredClientRepository
                )
            ).authorizationServerSettings(endpoints).tokenGenerator(JwtGenerator(NimbusJwtEncoder(jwkSource())))
    }
    return http.build()
}

2. 修正数据库中客户端密钥的存储格式

Spring Authorization Server要求客户端密钥必须携带密码编码器前缀(如{noop}、{bcrypt}),否则会默认使用BCrypt编码器验证,导致明文secret无法匹配。

确保数据库中client_secret字段的值是{noop}secret,而非单纯的secret。

3. 验证客户端认证方法的一致性

确认数据库中客户端的client_authentication_methods字段包含对应的认证方法:使用CLIENT_SECRET_BASIC时需包含client_secret_basic,使用CLIENT_SECRET_POST时需包含client_secret_post,保证配置与请求方式一致。

4. 开启调试日志排查细节

添加调试日志配置,查看认证过程的详细错误信息:

logging:
  level:
    org.springframework.security: DEBUG
    org.springframework.security.oauth2: DEBUG

日志会输出客户端查找、密钥验证的具体流程,帮助定位是否存在客户端不存在、密钥不匹配等深层问题。


内容的提问来源于stack exchange,提问作者OmniCoder77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:29:53