Search code examples
angularspring-bootkeycloakspring-cloud-gateway

How to get keycloak token using Angular -> Spring Boot Oauth2 -> Keycloak


I have a angular application as front end and spring boot as backend technology and as authorization server I am using keycloak 12.0.4.

I don't want to ues keycloak adapter for angular and spring boot, I want to use plain oauth2 oauth/token so that I can change my authorization server say for eg from keycloak to okta without much change code.

I can directly hit keycloak token_endpoint using postman and get the token by passing username, password, client_credentials

http://localhost:8080/auth/realms/dev/protocol/openid-connect/token

But using angular if I hit token_endpoint then all together I get a different issue of CROS and I tried proxy.config.json in angular and also set web-origin * in keycloak but that not working but basically I don't want to hit keycloak directly I want to go through spring boot oauth2

Access to XMLHttpRequest at 'http://127.0.0.1:8080/auth/realms/dev/protocol/openid-connect/token' from origin 'http://127.0.0.1:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. login.component.ts:37 .

Below is my application.yml file

server:
  port: 8181
spring:
  application:
    name: cloudgateway
  security:
     oauth2:
      client:
        registration:
          keycloak:
            client-id: myadmin-service
            client-secret: 4c7388e6-a8d9-403a-a5d4-416be4163b93
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            provider: keycloak
         provider:
           keycloak:
           token-uri: http://localhost:8080/auth/realms/dev/protocol/openid-connect/token
           issuer-uri: http://localhost:8080/auth/realms/dev
           authorization-uri: http://localhost:8080/auth/realms/dev/protocol/openid-connect/auth
           user-info-uri: http://localhost:8080/auth/realms/dev/protocol/openid-connect/userinfo
         resourceserver:
          jwt:
            issuer-uri: http://localhost:8080/auth/realms/dev
            jwk-set-uri: http://localhost:8080/auth/realms/dev/protocol/openid-connect/certs
 

Pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</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-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </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>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

What is the configuration that I am missing on the above spring boot.


Solution

  • You can configure WebSecurity to populate security-context with JwtAuthenticationToken (sample here) but this implementation is rather poor and requires quite some Java conf.

    I wrote a portable OIDC Authentication implementation with an interface almost as rich as KeycloakAuthenticationToken but compatible with any OpenID Connect authorisation-server: OAuthentication<OpenidClaimSet> (tutorial here)

    Within Angular, I use angular-auth-oidc-client.

    P.S. This git repo also contains annotations to easily populate JUnit security-context with the Authentication implementation you choose (see @WithMockOidcAuth, @WithMockJwtAuth or @WithMockKeycloakAuth)