Postman报invalid_client,90%是client_secret未加密或配错;Spring Cloud OAuth2要求client_secret必须经BCryptPasswordEncoder编码,明文配置会触发“Encoded password does not look like BCrypt”警告并返回该错误。

Postman 报 invalid_client,90% 是 client_secret 没配对或没加密 —— 不是 Postman 问题,是服务端校验失败的明确信号。
client_secret 明文写进 Spring Security 配置会触发 invalid_client
Spring Cloud OAuth2(尤其是 spring-security-oauth2 2.5+)默认要求 client_secret 必须经 BCryptPasswordEncoder 编码。如果你在 ClientDetailsServiceConfigurer 中直接传入明文字符串(比如 .secret("my-secret")),服务端日志会打出警告:Encoded password does not look like BCrypt,随后返回 invalid_client。
正确做法是显式调用编码器:
clients.inMemory()
.withClient("ecommerce-app")
.secret(passwordEncoder.encode("my-secret")) // ← 必须 encode
.authorizedGrantTypes("authorization_code")
.scopes("read_profile");
- 别用
noop或plaintext编码器,OAuth2 规范禁止明文存储 client_secret - 如果用的是
@EnableAuthorizationServer(已废弃但仍在用),确保passwordEncoderBean 已注入并生效 - 编码后的密文以
$2a$、$2b$或$2y$开头,长度约 60 字符;不是这个格式就说明没编对
Postman OAuth 2.0 配置里 client_secret 填错了
Postman 的 OAuth 2.0 认证面板中,Client Secret 字段必须和服务器端编码后存储的值完全一致。常见错误包括:
Postman 12.27.7 Windows x64 官方安装包,适用于 API 设计、调试、测试与协作。该系列包含 Enterprise 云端性能测试静态 IP 出口能力,以及接口规范标签管理改进,适合受限网络测试与规范资源组织场景。
- 复制时多空格或换行(尤其从 IDE 或日志里复制)
- 混淆了
Client Secret Value和Secret ID(Azure AD 场景下,只填 Value) - 环境变量未正确解析:检查 Postman 环境里
{{client_secret}}是否真实存在且非空 - 用了 URL 编码过的 secret(比如含
+、/),而服务端未做解码 —— 应该在 Postman 中填原始值,让框架自动处理编码
token 端点请求头或参数不匹配导致校验失败
/oauth/token 接口对客户端凭证的校验非常严格,以下任一条件不满足都会返回 invalid_client:
- 请求必须是
POST,且Content-Type: application/x-www-form-urlencoded -
client_id和client_secret必须作为表单参数传(不是 Header,也不是 JSON body) - 若使用 Basic Auth 方式传凭据,Header 格式必须为:
Authorization: Basic base64(client_id:client_secret),注意冒号不能漏 - 授权模式(
grant_type)必须和服务端配置的authorizedGrantTypes匹配,比如服务端只允许authorization_code,你却发password就会失败
刷新 token 时也报 invalid_client?重点查 Refresh Token 生命周期
调用 /oauth/token?grant_type=refresh_token 时出 invalid_client,除了 client_secret 错误外,更隐蔽的原因是:
- Refresh Token 本身已失效(过期或被撤销),但某些旧版 Spring Security 实现会把这类错误统一包装成
invalid_client而非invalid_grant - 服务端配置了
reuseRefreshToken = false,而 Postman 在刷新时重复用了同一个 refresh_token - 客户端未在 refresh 请求中携带 scope(即使原 access_token 有 scope,refresh 时也需显式声明,否则部分实现会拒收)
最稳妥的验证方式:跳过 Postman 自动刷新,手动用新请求调 /oauth/token,把 refresh_token 当普通参数传,观察响应体是否明确返回 invalid_grant —— 如果是,说明问题不在 client 凭据,而在 token 本身。

















