How to get Linkedin OAuth working in Spring Boot
Asked Answered
M

3

6

Need help to have Login with Linkedin in a Spring boot 2.1.6.RELEASE project with Spring OAuth2. Java version is 11

Google and Github are pretty straightforward and work in the same project. I tried a couple of sample codes in Spring-Social but they failed due to different Spring boot version.

Below application.properties does not work (also tried client-authentication-method=post), and gets redirected back after authorization code is retrieved from linkedin (authorization code is valid, with which I can get access token from Postman).

spring.security.oauth2.client.registration.linkedin.provider=linkedin
spring.security.oauth2.client.registration.linkedin.client-name=Linkedin
spring.security.oauth2.client.registration.linkedin.client-id=******
spring.security.oauth2.client.registration.linkedin.client-secret=******
spring.security.oauth2.client.registration.linkedin.redirect-uri=*****
spring.security.oauth2.client.registration.linkedin.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.linkedin.client-authentication-method=form
spring.security.oauth2.client.registration.linkedin.scope=r_emailaddress,r_liteprofile
spring.security.oauth2.client.provider.linkedin.authorization-uri=https://www.linkedin.com/oauth/v2/authorization
spring.security.oauth2.client.provider.linkedin.token-uri=https://www.linkedin.com/oauth/v2/accessToken
spring.security.oauth2.client.provider.linkedin.user-info-uri=https://api.linkedin.com/v2/me
spring.security.oauth2.client.provider.linkedin.user-info-authentication-method=post

SecurityConfig class (Also tried without antMatchers):

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("*linkedin*").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .oauth2Login();
    }

There is no error, and after code query parameter is returned back to Spring along with state, it gets redirected back to Spring login.

Thanks

Medley answered 8/11, 2019 at 4:47 Comment(0)
A
3

My working configuration:

spring:
  security:
    oauth2:
      client:
        registration:
          linkedin:
            client-id: ????
            client-secret: ????
            scope:  r_liteprofile, r_emailaddress
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            client-name: LinkedIn
            client-authentication-method: post

        provider:
          linkedin:
            authorization-uri: https://www.linkedin.com/oauth/v2/authorization
            token-uri: https://www.linkedin.com/uas/oauth2/accessToken
            user-info-uri: https://api.linkedin.com/v2/me
            jwk-set-uri:
            user-name-attribute: id

Latest Spring: org.springframework.security:spring-security-oauth2-client:5.2.2.RELEASE

Aubry answered 11/5, 2020 at 9:12 Comment(2)
in my case it's not working could you please share some source code of it. ThanksTonneson
I am stuck at http://localhost:8080/oauth2/code/linkedin?code=AQSV... flow is not moving further. Any help appreciated. Thank you.Tonneson
S
2

The problem/cause is that the tokenType is missing.

To reproduce set a breakpoint at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter at this place:

    catch (AuthenticationException failed) {
        // Authentication failed
        unsuccessfulAuthentication(request, response, failed);

        return;
    }

Then you will see failed = this exception:

org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: Error while extracting response for type [class org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: An error occurred reading the OAuth 2.0 Access Token Response: tokenType cannot be null; nested exception is java.lang.IllegalArgumentException: tokenType cannot be null

One "solution" for this is to add a converter that adds the tokenType. Have a look at https://github.com/spring-projects/spring-security/issues/5983#issuecomment-430620308 and add this call .tokenEndpoint().accessTokenResponseClient(authorizationCodeTokenResponseClient()) plus the implementation of authorizationCodeTokenResponseClient() at the end of that mentioned github-link ( https://github.com/jzheaux/messaging-app/blob/master/client-app/src/main/java/sample/config/SecurityConfig.java#L71 ) plus this class https://github.com/jzheaux/messaging-app/blob/master/client-app/src/main/java/sample/web/CustomAccessTokenResponseConverter.java .

... and for the sake of completeness: this is my configuration snippet from application.properties:

spring.security.oauth2.client.registration.linkedin.client-id: ????
spring.security.oauth2.client.registration.linkedin.client-secret: ????
spring.security.oauth2.client.registration.linkedin.scope=r_emailaddress,r_liteprofile
spring.security.oauth2.client.registration.linkedin.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.linkedin.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.linkedin.client-name = LinkedIn
spring.security.oauth2.client.registration.linkedin.provider=linkedin
spring.security.oauth2.client.registration.linkedin.client-authentication-method = post
spring.security.oauth2.client.provider.linkedin.authorization-uri=https://www.linkedin.com/oauth/v2/authorization
spring.security.oauth2.client.provider.linkedin.token-uri=https://www.linkedin.com/oauth/v2/accessToken
spring.security.oauth2.client.provider.linkedin.user-info-uri=https://api.linkedin.com/v2/me
spring.security.oauth2.client.provider.linkedin.jwk-set-uri = 
spring.security.oauth2.client.provider.linkedin.user-name-attribute = id
spring.security.oauth2.client.provider.linkedin.user-info-authentication-method=post
Spellbind answered 9/7, 2020 at 20:58 Comment(0)
G
0

This issue can be easily fixed by WebClientReactiveAuthorizationCodeTokenResponseClient bean customizing - you need to modify the response and add the "token_type: "Bearer" field there. This can be implemented using ExchangeFilterFunction.

So, here an example, let's create a simple DTO:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class Oauth2TokenResponseDTO(

        val accessToken: String,
        val expiresIn: Int,
        val tokenType: String = OAuth2AccessToken.TokenType.BEARER.value

)

Then, in your reactive-security config just add next:

private fun modifyResponse(): ExchangeFilterFunction {
        return ExchangeFilterFunction.ofResponseProcessor { response: ClientResponse ->
            response.bodyToMono(Oauth2TokenResponseDTO::class.java)
                    .map { objectMapper.writeValueAsString(it) }
                    .map { ClientResponse.from(response).body(it).build() }
        }
    }

And last one:

@Bean
fun webClientReactiveAuthorizationCodeTokenResponseClient(): WebClientReactiveAuthorizationCodeTokenResponseClient {
    val tokenResponseClient = WebClientReactiveAuthorizationCodeTokenResponseClient()
    val webClient = WebClient.builder()
            .clientConnector(ReactorClientHttpConnector(HttpClient.create().wiretap(true)))
            .filter(modifyResponse())
            .build()
    tokenResponseClient.setWebClient(webClient)
    return tokenResponseClient
}

P.S.: note that if you have another oauth2 providers - you need to implement a filter method in ExchangeFilterFunction.

Ganister answered 29/9, 2020 at 10:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.