Search code examples
javaoauth-2.0amazon-cognitospring-webfluxspring-security-oauth2

Autogenerated OAuth2 login page for AWS Cognito in reactive Spring Boot application fails


I am facing an authentication issue in a reactive Spring Boot application using OAuth2 and AWS Cognito. Namely, I configured my app like it's suggested in post here but the problem is that the default login page is failing while authentication attempts or visits. For redirect-uri=http://localhost:8080/login/oauth2/code/cognito I am getting fitness_uri1 For redirect-uri=https://fitnesstest.auth.eu-central-1.amazoncognito.com/login/cognito I am receiving

An error was encountered with the requested page.

Funnily enough, I can receive the tokens via postman for the below client-id, client-secret and callback URL but somehow from the spring boot application, it's not possible.

my first approach of application.properties look like:

spring.security.oauth2.client.registration.cognito.client-id=TOP-SECRET-CLIENT-ID
spring.security.oauth2.client.registration.cognito.client-secret=TOP-SECRET
spring.security.oauth2.client.registration.cognito.client-name=fitnesstest
spring.security.oauth2.client.registration.cognito.provider=cognito
spring.security.oauth2.client.registration.cognito.scope=openid
spring.security.oauth2.client.registration.cognito.redirect-uri=http://localhost:8080/login/oauth2/code/cognito
spring.security.oauth2.client.registration.cognito.authorization-grant-type=authorization_code
#provider
spring.security.oauth2.client.provider.cognito.authorization-uri=https://fitnesstest.auth.eu-central-1.amazoncognito.com/oauth2/authorize
spring.security.oauth2.client.provider.cognito.token-uri=https://fitnesstest.auth.eu-central-1.amazoncognito.com/oauth2/token
spring.security.oauth2.client.provider.cognito.user-info-uri=https://fitnesstest.auth.eu-central-1.amazoncognito.com/oauth2/userInfo
spring.security.oauth2.client.provider.cognito.jwk-set-uri=https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_TOP-SECRET-POOL-ID/.well-known/jwks.json
spring.security.oauth2.client.provider.cognito.user-name-attribute=cognito:username

my WebSecurityConfiguration looks like:

@Configuration
@EnableWebFluxSecurity
@PropertySource("classpath:security.properties")
public class WebSecurityConfiguration {

  public static final String ADMIN_LOGIN_URL = "/auth/login";
  public static final String USER_LOGIN_URL = "/auth/loginUser";
  public static final String LOGOUT_URL = "/auth/signOut";
  public static final String SIGNUP_BY_ADMIN_URL = "/auth/signUp";
  public static final String SIGNUP_URL = "/auth/registration";
  public static final String API_DOCS_URL = "/v2/api-docs";
  public static final String NUTRITION_URL = "/nutrition/api/**";
  public static final String OAUTH2_URL = "/oauth/**";
  public static final String LOGIN_URL = "/login";
  public static final String DEFAULT_URL = "/";

  @Bean
  public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {

    httpSecurity
        .cors()
        .and()
        .csrf()
        .disable()
        .httpBasic()
        .disable()
        .authorizeExchange()
        .pathMatchers("/login**", "/oauth2/authorization/**")
        .permitAll()
        .anyExchange()
        .authenticated()
        .and()
        .oauth2Login();

    return httpSecurity.build();
  }
}

my pom.xml looks like this:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.0</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.fitnessgo</groupId>
  <artifactId>api-gateway</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>api-gateway</name>
  <description>api-gateway</description>
  <properties>
    <java.version>17</java.version>
    <spring-cloud.version>2021.0.0</spring-cloud.version>
    <nimbus-jose-jwt>9.15.2</nimbus-jose-jwt>
    <aws.sdk.version>1.12.111</aws.sdk.version>

  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-sleuth</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-oauth2-client</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-oauth2-jose</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!--OTHERS-->
    <dependency>
      <groupId>com.nimbusds</groupId>
      <artifactId>nimbus-jose-jwt</artifactId>
      <version>${nimbus-jose-jwt}</version>
    </dependency>

    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-api</artifactId>
      <version>0.11.2</version>
    </dependency>

    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-impl</artifactId>
      <version>0.11.2</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-jackson</artifactId>
      <version>0.11.2</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
      <!--<exclusions>
        <exclusion>
          <groupId>io.lettuce</groupId>
          <artifactId>lettuce-core</artifactId>
        </exclusion>
      </exclusions>-->
    </dependency>

    <!--AWS-->
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-cognitoidp</artifactId>
      <version>${aws.sdk.version}</version>
    </dependency>

    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk</artifactId>
      <version>${aws.sdk.version}</version>
    </dependency>

    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-core</artifactId>
      <version>${aws.sdk.version}</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.projectreactor</groupId>
      <artifactId>reactor-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <excludes>
            <exclude>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
            </exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

</project>

EDIT: I tried to create a new project with only the oauth2 + spring security configuration and I am still facing the same problem.

I am completely confused why via postman I can receive a token and it's recognizable in jwt.io but from the spring boot application, it's now working as expected. I will be grateful for suggestions on how to reach the desired goal. Cheers.


Solution

  • Turned out that there is a chance to debug Invalid credentials error for OAuth2 approach. After a suggestion from https://stackoverflow.com/a/62917085/10596295, I debugged the application and realized that there is a problem with the property user-name-attribute. My final version of application.yml looks like this:

    spring:
      security:
        oauth2:
          client:
            registration:
              cognito:
                client-id: XXX
                client-secret: XXX
                scope: openid
                redirect-uri: http://localhost:8080/login/oauth2/code/cognito
                clientName: fitnesstest
            provider:
              cognito:
                issuerUri: https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXX