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

Spring Security OAuth2集成Procore客户端认证失败求助

Procore OAuth2登录客户端认证失败问题排查

我正在开发一个支持跳转至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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:13:18