1

I'm looking to developed a Spring OAuth2RestTemplate code and taken a reference from Access tokens using 2 legged Oauth 2.0 and Apache OauthClient.

There are two suggestions been given, First suggestion using Apache Oltu worked absolutely fine to me. Now, I am looking to developed second option which is using the Spring Oauth2 RestTemplate.

The error I am getting:-

WARN : org.springframework.web.client.RestTemplate - POST request for "https://graph.facebook.com/oauth/access_token" resulted in 400 (Bad Request); invoking error handler
Exception in thread "main" error="access_denied", error_description="Error requesting access token."
    at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:145)
    at org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider.obtainAccessToken(ClientCredentialsAccessTokenProvider.java:44)
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:142)
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:118)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:564)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:529)
    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:329)
    at com.apache.oltu.RestFacebookController.authenticate(RestFacebookController.java:46)
    at com.apache.oltu.RestFacebookController.main(RestFacebookController.java:52)
Caused by: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
    at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:244)
    at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:615)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:573)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:537)
    at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137)
    ... 12 more

I tried to debug the application for several weeks, and finally decided to post it on stackoverflow.com. Here is what I've developed code

import java.util.Arrays;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/restfacebook")
public class RestFacebookController {
    private static final Logger logger = LoggerFactory.getLogger(RestFacebookController.class);

    private String CLIENT_SECRET = "33b17e044ee6a4fa383f46ec6e28ea1d";
    private String CLIENT_ID = "233668646673605";

    @RequestMapping(value = "/auth", method = RequestMethod.GET)
    public void authenticate() {
        logger.debug("In a Authenticate() method"); 
        ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
        resourceDetails.setClientSecret(CLIENT_SECRET);
        resourceDetails.setClientId(CLIENT_ID);
        resourceDetails.setAccessTokenUri("https://graph.facebook.com/oauth/access_token");
        resourceDetails.setScope(Arrays.asList("email,offline_access,user_about_me,user_birthday,read_friendlists"));
        resourceDetails.setTokenName("code");

        JSONObject request = new JSONObject();
        request.put("resourceDetails", resourceDetails);

        OAuth2RestTemplate oAuthRestTemplate = new OAuth2RestTemplate(resourceDetails);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType( MediaType.APPLICATION_JSON );

        // Sample POST Method
        HttpEntity<String> reqEntity = new HttpEntity<String>(resourceDetails.toString(), headers);
        String postUri = "https://www.facebook.com/dialog/oauth";
        String postResult = oAuthRestTemplate.postForObject(postUri, reqEntity, String.class);
        System.out.println(postResult);
    }
}
}

If I followed Dave's suggested code below, Also Dave's code seems working, but why this not? I don't see any differences in concept as such.

private String CLIENT_SECRET = "33b17e044ee6a4fa383f46ec6e28ea1d";
    private String CLIENT_ID = "233668646673605";

    @RequestMapping(value = "/auth", method = RequestMethod.GET)
    public void authenticate() {
        logger.debug("In a Authenticate() method"); 
        AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
        details.setId("facebook");
        details.setClientId(CLIENT_ID);
        details.setClientSecret(CLIENT_SECRET);
        details.setAccessTokenUri("https://graph.facebook.com/oauth/access_token");
        details.setUserAuthorizationUri("https://www.facebook.com/dialog/oauth");
        details.setTokenName("oauth_token");
        details.setAuthenticationScheme(AuthenticationScheme.query);
        details.setClientAuthenticationScheme(AuthenticationScheme.form);

        OAuth2RestTemplate oAuthRestTemplate = new OAuth2RestTemplate(details);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType( MediaType.APPLICATION_JSON );

        // Sample POST Method
        HttpEntity<String> reqEntity = new HttpEntity<String>(details.toString(), headers);
        String postUri = "https://www.facebook.com/dialog/oauth";
        String postResult = oAuthRestTemplate.postForObject(postUri, reqEntity, String.class);
        System.out.println(postResult);
    }

Then I got another error, which seems expected, Now how we can get over this error?

Exception in thread "main" org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: A redirect is required to get the users approval
    at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.getRedirectForAuthorization(AuthorizationCodeAccessTokenProvider.java:347)
    at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:194)
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:142)
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:118)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:564)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:529)
    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:329)
    at com.apache.oltu.RestFacebookController.authenticate(RestFacebookController.java:48)
    at com.apache.oltu.RestFacebookController.main(RestFacebookController.java:54)

pom.xml:

<properties>
        <org.springframework-version>4.1.5.RELEASE</org.springframework-version>
        <org.aspectj-version>1.8.5</org.aspectj-version>
    </properties>

    <dependencies>
        <!-- Spring Context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework-version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Spring Web MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>

        <!-- AspectJ -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${org.aspectj-version}</version>
        </dependency>

        <!-- Module for providing OAuth2 support to Spring Security -->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.0.7.RELEASE</version>
        </dependency>
        <!-- Apache Log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.mail</groupId>
                    <artifactId>mail</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
            <scope>runtime</scope>
        </dependency>

        <!-- @Inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
    </dependencies>
Community
  • 1
  • 1
  • You might want to check this post out: http://stackoverflow.com/questions/26280249/facebook-v2-1-oauth-authorize-do-not-redirect-to-v2-1-dialog-oauth – Benj F Jun 19 '15 at 21:12

1 Answers1

0

You might need to set the authentication scheme for your client (Facebook probably still doesn't accept header authentication as recommended by the spec). Example (https://github.com/spring-projects/spring-security-oauth/blob/master/samples/oauth2/tonr/src/main/java/org/springframework/security/oauth/examples/config/WebMvcConfig.java#L185)

resourceDetails.setAuthenticationScheme(AuthenticationScheme.query);
Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • A `RedirectRequiredException` is normally handled by a filter. If you have an `OAuth2ClientContextFilter` you should never see one. The samples and the documentation should be quite easy to follow on this. – Dave Syer Apr 23 '15 at 21:19
  • Dave - I'm not quite sure of fixing the "A redirect is required to get the users approval". Currently I'm not using OAuth2ClientContextFilter in the code, per my code, just doing simple POST through RestTemplate which have been worked..What you think? I will try to use OAuth2ClientContextFilter as you suggested though. –  Apr 24 '15 at 05:30
  • Unless your system only has one user you need a filter (assuming it is a webapp). It's all explicit in the docs and in the tonr sample I believe. – Dave Syer Apr 24 '15 at 07:02
  • I don't understand the problem. You are using Spring MVC so you are probably in a regular servlet-based webapp, right? – Dave Syer Apr 24 '15 at 14:08