Spring Security OAuth2集成Procore客户端认证失败求助
我正在开发一个支持跳转至Procore开发者门户、使用Procore账号登录的登录页面。点击“使用Procore登录”按钮时,出现错误:
Procore Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method
已反复核对client id、client secret及redirect url,确认在SecurityConfig文件和application.properties中均一致,当前使用沙箱凭证。以下是配置代码:
SecurityConfig代码
package com.Lumber.LumberIntegration.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.web.SecurityFilterChain; @Configuration public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorizeRequests -> authorizeRequests .requestMatchers("/index.html", "/login").permitAll() .anyRequest().authenticated() ) .oauth2Login(oauth2Login -> oauth2Login .loginPage("/index.html") .defaultSuccessUrl("/home.html", true) .failureUrl("/index.html?error") ) .csrf(csrf -> csrf.disable()); return http.build(); } @Bean public ClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(procoreClientRegistration()); } private ClientRegistration procoreClientRegistration() { return ClientRegistration.withRegistrationId("procore") .clientId("o9ABPysGyDZxQg1sI254lsZKY9c4dx5TwMmE3E7yV9A") .clientSecret("myClientSecret") .scope("openid", "profile", "email") .authorizationUri("https://login.procore.com/oauth/authorize") .tokenUri("https://login.procore.com/oauth/token") .userInfoUri("https://app.procore.com/vapid/me") .userNameAttributeName("email") .clientName("Procore") .redirectUri("http://localhost:3000/login/oauth2/code/procore") .authorizationGrantType(org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE) .build(); } }
Maven依赖配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://www.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lumber</groupId> <artifactId>lumber-integration</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.1</version> <relativePath /> </parent> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-core</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-core</artifactId> <version>1.13.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>provided</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.3.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>3.3.1</version> </plugin> </plugins> </build> <repositories> <repository> <id>central</id> <url>https://repo.maven.apache.org/maven2/</url> </repository> </repositories> </project>
排查方案
1. 强制使用Basic认证方式
Procore的OAuth2服务要求获取token时使用Basic认证(将client_id和client_secret通过Base64编码放入Authorization请求头),而Spring Security OAuth2 Client默认可能将认证信息放在请求参数中,不符合Procore要求。修改procoreClientRegistration()方法,添加认证方式配置:
private ClientRegistration procoreClientRegistration() { return ClientRegistration.withRegistrationId("procore") .clientId("o9ABPysGyDZxQg1sI254lsZKY9c4dx5TwMmE3E7yV9A") .clientSecret("myClientSecret") // 新增:指定使用Basic认证 .clientAuthenticationMethod(org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .scope("openid", "profile", "email") .authorizationUri("https://login.procore.com/oauth/authorize") .tokenUri("https://login.procore.com/oauth/token") .userInfoUri("https://app.procore.com/vapid/me") .userNameAttributeName("email") .clientName("Procore") .redirectUri("http://localhost:3000/login/oauth2/code/procore") .authorizationGrantType(org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE) .build(); }
2. 验证沙箱端点正确性
确认Procore沙箱环境的token端点是否为https://login.procore.com/oauth/token,部分平台沙箱与生产端点存在差异,需核对官方文档确认。
3. 严格匹配redirect_uri
Procore对redirect_uri的匹配要求极高,需确保:
- 协议(http/https)完全一致(沙箱可用http,生产必须用https)
- 端口号与应用实际运行端口一致(当前配置为3000)
- 路径完全匹配,包括大小写,必须与Procore开发者后台配置的redirect_uri完全相同
4. 开启调试日志排查请求细节
在application.properties中添加日志配置,查看请求token时的参数与认证头是否正确:
logging.level.org.springframework.security=DEBUG logging.level.org.springframework.web=DEBUG
通过日志确认请求是否携带了正确的Authorization头,以及参数是否符合Procore要求。
5. 确认沙箱应用状态
登录Procore开发者门户,检查:
- 沙箱应用是否处于激活状态,未被禁用或审核中
- 应用配置的权限范围(scope)与代码中
openid, profile, email完全一致
内容的提问来源于stack exchange,提问作者AppleDev3

