Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: Retrieving access code server side

  1. #1
    Join Date
    May 2005
    Location
    BEEK, The Netherlands
    Posts
    230

    Default Retrieving access code server side

    Does the Spring Social Facebook provider support retrieving a access token via:
    graph.facebook.com/oauth/access_token?client_id=YOUR_APP_ID&client_secret=Y OUR_APP_SECRET&grant_type=client_credentials

    I need to retrieve the access code this way as I want a backend server to connect with Facebook to execute various fql queries.

    This is also explained in server-side-login:
    http://developers.facebook.com/docs/...er-side-login/

    And is e.g. supported in fbrest library like: http://restfb.com/javadoc/com/restfb....lang .String, java.lang.String)


    I wonder if Spring Social Facebook supports this or that should create a feature request in jira?

  2. #2
    Join Date
    Aug 2004
    Posts
    1,072

    Default

    It does support this in OAuth2Operations.authenticateClient(). (You don't have to pass in the client's credentials to this method, because they are already set on OAuth2Template at construction time.)

    Note that this is *NOT* integrated into the connection framework. In other words, there's no support for persisting this access token because the connection framework acts on behalf of the user but client credential authorization is acting on behalf of the application itself.

    The other thing to note is that this is a relatively new addition and is not part of Spring Social 1.0.x. It is available in 1.1.0.M1 and the latest snapshots, however.
    Craig Walls
    Spring Social Project Lead

  3. #3
    Join Date
    May 2005
    Location
    BEEK, The Netherlands
    Posts
    230

    Default

    Hi Craig,

    Don't know if I can follow this completely. Should I create a OAuth2Template instead of a FacebookTemplate?
    How can I hook these up then? At end I need FacebookTemplate to have access to Graph operations.

    Note that the TwitterTemplate can be created with consumer key/secret and token/secret.
    I was looking for something similar with the FacebookTemplate.

    Note2: I'm on 1.1.0.M1 anyway so it's ok for me to use latest.

  4. #4
    Join Date
    Aug 2004
    Posts
    1,072

    Default

    Yes, you would create an OAuth2Template, use the authenticateClient() to get the access token (in an AccessGrant instance), then use the access token to construct a FacebookTemplate. Something like this:

    Code:
    OAuth2Template oauth = new OAuth2Template(clientId, clientSecret, "https://www.facebook.com/dialog/oauth", "https://graph.facebook.com/oauth/access_token");
    AccessGrant accessGrant = oauth.authenticateClient();
    FacebookTemplate facebook = new FacebookTemplate(accessGrant.getAccessToken());

    You can't do this directly in FacebookTemplate only because the client credentials grant is an OAuth2 concern...not a Facebook concern. Another way of looking at it is that the OAuth templates are primarily for connection-time and the API binding templates are for API time.

    The only reason you must pass the client credentials into TwitterTemplate is because they are required for creating the Authorization header in all requests to the API...per the OAuth 1.0(a) spec. But Facebook, being based on OAuth 2, doesn't require the client's credentials to make API calls, so they are not required when constructing FacebookTemplate.

    One thing that just occurred to me, though: What operations are you wanting to perform with the client token? Not many (or any) of the operations in FacebookTemplate are for client tokens. Of course, you could create a FacebookTemplate and then use the operations in GraphApi or fetch its RestOperations and do whatever you want. But I'd be curious to know what client operations you intend to perform.

    If there's some client operations you would like to be added to FacebookTemplate, let me know via Jira or (better yet) with a pull request. We've been focused on FacebookTemplate's user operations, but I agree that it should be expanded to cover client operations.
    Craig Walls
    Spring Social Project Lead

  5. #5
    Join Date
    May 2005
    Location
    BEEK, The Netherlands
    Posts
    230

    Default

    Quote Originally Posted by habuma View Post
    One thing that just occurred to me, though: What operations are you wanting to perform with the client token? Not many (or any) of the operations in FacebookTemplate are for client tokens. Of course, you could create a FacebookTemplate and then use the operations in GraphApi or fetch its RestOperations and do whatever you want. But I'd be curious to know what client operations you intend to perform.

    If there's some client operations you would like to be added to FacebookTemplate, let me know via Jira or (better yet) with a pull request. We've been focused on FacebookTemplate's user operations, but I agree that it should be expanded to cover client operations.
    I want to use FQL queries as this fits best at the moment.
    Basically I want to retrieve a bunch of pages in 1 call and retrieve some fields (e.g. number of "likes").

  6. #6
    Join Date
    Aug 2004
    Posts
    1,072

    Default

    I see. So yeah, I suppose that there are some FQL queries that will work just fine with client credentials.

    If you see an opportunity to extend the API binding with more client-specific operations, let me know. As I said, client-specific operations haven't been in the focus thus far, but I'm starting to see more use for them and want to be sure they're covered.
    Craig Walls
    Spring Social Project Lead

  7. #7

    Default

    Quote Originally Posted by habuma View Post
    ...
    Code:
    OAuth2Template oauth = new OAuth2Template(environment.getProperty("facebook.clientId"),
                            environment.getProperty("facebook.clientSecret"),
    "https://www.facebook.com/dialog/oauth", "https://graph.facebook.com/oauth/access_token");
    AccessGrant accessGrant = oauth.authenticateClient();
    FacebookTemplate facebook = new FacebookTemplate(accessGrant.getAccessToken());
    Hi Graig.
    I'm trying to get app access token for making subsequent 'app request' call :
    facebook.publish(facebookUserId, "apprequests", data);
    The call is 'App to User request' for user who already had canvas app installed in his fb profile.
    While calling oauth.authenticateClient(); I'm getting error in log (org.apache.http package) like:

    11:41:32.563 [http-apr-8080-exec-6] DEBUG o.a.h.i.c.PoolingClientConnectionManager - Connection request: [route: {s}->https://graph.facebook.com][total kept alive: 0; route allocated: 0 of 5; total allocated: 0 of 100]
    11:41:32.564 [http-apr-8080-exec-6] DEBUG o.a.h.i.c.PoolingClientConnectionManager - Connection leased: [id: 1][route: {s}->https://graph.facebook.com][total kept alive: 0; route allocated: 1 of 5; total allocated: 1 of 100]
    11:41:33.672 [http-apr-8080-exec-6] DEBUG o.a.h.i.c.DefaultClientConnectionOperator - Connecting to graph.facebook.com:443
    11:41:34.087 [http-apr-8080-exec-6] DEBUG o.a.h.c.protocol.RequestAddCookies - CookieSpec selected: best-match
    11:41:34.088 [http-apr-8080-exec-6] DEBUG o.a.h.c.protocol.RequestAuthCache - Auth cache not set in the context
    11:41:34.089 [http-apr-8080-exec-6] DEBUG o.a.h.c.p.RequestProxyAuthentication - Proxy auth state: UNCHALLENGED
    11:41:34.090 [http-apr-8080-exec-6] DEBUG o.a.h.impl.client.DefaultHttpClient - Attempt 1 to execute request
    11:41:34.090 [http-apr-8080-exec-6] DEBUG o.a.h.i.conn.DefaultClientConnection - Sending request: POST /oauth/access_token HTTP/1.1
    11:41:34.091 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "POST /oauth/access_token HTTP/1.1[\r][\n]"
    11:41:34.092 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "Accept: application/json, application/*+json[\r][\n]"
    11:41:34.093 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "Content-Type: application/x-www-form-urlencoded[\r][\n]"
    11:41:34.093 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "Authorization: Basic NTEzODgzNDc4NjMzNTkyOjYzYThhOWM2Z................. .ZWJhOWZh[\r][\n]"
    11:41:34.094 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "Content-Length: 29[\r][\n]"
    11:41:34.095 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "Host: graph.facebook.com[\r][\n]"
    11:41:34.095 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "Connection: Keep-Alive[\r][\n]"
    11:41:34.096 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "User-Agent: Apache-HttpClient/4.2.2 (java 1.5)[\r][\n]"
    11:41:34.097 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "[\r][\n]"
    11:41:34.097 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> POST /oauth/access_token HTTP/1.1
    11:41:34.097 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> Accept: application/json, application/*+json
    11:41:34.098 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> Content-Type: application/x-www-form-urlencoded
    11:41:34.098 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> Authorization: Basic NTEzODgzNDc4NjMzNTkyOjYzYThhOWM2ZWU..............D BhZWJhOWZh
    11:41:34.099 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> Content-Length: 29
    11:41:34.099 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> Host: graph.facebook.com
    11:41:34.100 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> Connection: Keep-Alive
    11:41:34.100 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - >> User-Agent: Apache-HttpClient/4.2.2 (java 1.5)
    11:41:34.101 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - >> "grant_type=client_credentials"
    11:41:34.296 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "HTTP/1.1 400 Bad Request[\r][\n]"
    11:41:34.297 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Access-Control-Allow-Origin: *[\r][\n]"
    11:41:34.299 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Cache-Control: no-store[\r][\n]"
    11:41:34.300 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Content-Type: application/json[\r][\n]"
    11:41:34.301 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Expires: Sat, 01 Jan 2000 00:00:00 GMT[\r][\n]"
    11:41:34.302 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Pragma: no-cache[\r][\n]"
    11:41:34.303 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "WWW-Authenticate: OAuth "Facebook Platform" "invalid_client" "Missing client_id parameter."[\r][\n]"
    11:41:34.304 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "X-FB-Rev: 734528[\r][\n]"
    11:41:34.306 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "X-FB-Debug: yWIFgiWJPRfRNAUY3a4fpj2fIxM+D4upa0mE26+eYLo=[\r][\n]"
    11:41:34.307 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Date: Tue, 12 Feb 2013 09:41:36 GMT[\r][\n]"
    11:41:34.308 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Connection: keep-alive[\r][\n]"
    11:41:34.309 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "Content-Length: 87[\r][\n]"
    11:41:34.310 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "[\r][\n]"
    11:41:34.311 [http-apr-8080-exec-6] DEBUG o.a.h.i.conn.DefaultClientConnection - Receiving response: HTTP/1.1 400 Bad Request
    11:41:34.312 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << HTTP/1.1 400 Bad Request
    11:41:34.313 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Access-Control-Allow-Origin: *
    11:41:34.314 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Cache-Control: no-store
    11:41:34.315 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Content-Type: application/json
    11:41:34.316 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Expires: Sat, 01 Jan 2000 00:00:00 GMT
    11:41:34.317 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Pragma: no-cache
    11:41:34.320 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << WWW-Authenticate: OAuth "Facebook Platform" "invalid_client" "Missing client_id parameter."
    11:41:34.321 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << X-FB-Rev: 734528
    11:41:34.322 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << X-FB-Debug: yWIFgiWJPRfRN...........upa0mE26+eYLo=
    11:41:34.322 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Date: Tue, 12 Feb 2013 09:41:36 GMT
    11:41:34.323 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Connection: keep-alive
    11:41:34.324 [http-apr-8080-exec-6] DEBUG org.apache.http.headers - << Content-Length: 87
    11:41:34.326 [http-apr-8080-exec-6] DEBUG o.a.h.impl.client.DefaultHttpClient - Connection can be kept alive indefinitely
    11:41:34.327 [http-apr-8080-exec-6] WARN o.s.web.client.RestTemplate - POST request for "https://graph.facebook.com/oauth/access_token" resulted in 400 (Bad Request); invoking error handler
    11:41:34.330 [http-apr-8080-exec-6] DEBUG org.apache.http.wire - << "{"error":{"message":"Missing client_id parameter.","type":"OAuthException","code":101}}"
    11:41:34.331 [http-apr-8080-exec-6] DEBUG o.a.h.i.c.PoolingClientConnectionManager - Connection [id: 1][route: {s}->https://graph.facebook.com] can be kept alive indefinitely
    11:41:34.332 [http-apr-8080-exec-6] DEBUG o.a.h.i.c.PoolingClientConnectionManager - Connection released: [id: 1][route: {s}->https://graph.facebook.com][total kept alive: 1; route allocated: 1 of 5; total allocated: 1 of 100]
    11:41:38.560 [http-apr-8080-exec-6] ERROR c.i.w.c.e.EventRegisterController - Publishing REST error
    org.springframework.web.client.HttpClientErrorExce ption: 400 Bad Request
    at org.springframework.web.client.DefaultResponseErro rHandler.handleError(DefaultResponseErrorHandler.j ava:88) ~[spring-web-3.2.0.RELEASE.jar:3.2.0.RELEASE]
    There is something I don't quite understand...

    I debugged initalization public OAuth2Template(........)
    Code:
    	public OAuth2Template(String clientId, String clientSecret, String authorizeUrl, String authenticateUrl, String accessTokenUrl) {
    		Assert.notNull(clientId, "The clientId property cannot be null");
    		Assert.notNull(clientSecret, "The clientSecret property cannot be null");
    		Assert.notNull(authorizeUrl, "The authorizeUrl property cannot be null");
    		Assert.notNull(accessTokenUrl, "The accessTokenUrl property cannot be null");
    		this.clientId = clientId;
    		this.clientSecret = clientSecret;
    		String clientInfo = "?client_id=" + formEncode(clientId);
    		this.authorizeUrl = authorizeUrl + clientInfo;
    		if (authenticateUrl != null) {
    			this.authenticateUrl = authenticateUrl + clientInfo;
    		} else {
    			this.authenticateUrl = null;
    		}
    		this.accessTokenUrl = accessTokenUrl;
    		this.restTemplate = createRestTemplate();
    		if (!useParametersForClientAuthentication) {
    			restTemplate.getInterceptors().add(new PreemptiveBasicAuthClientHttpRequestInterceptor(clientId, clientSecret));
    		}
    	}
    The RED line is executed and I'm not sure if I initialize it correctly for my case.
    Last edited by blandger; Feb 12th, 2013 at 04:14 AM. Reason: added more clarification info
    Best regards.

  8. #8
    Join Date
    Aug 2004
    Posts
    1,072

    Default

    I don't think that the authenticateUrl matters here. It's fine that it's null. That URL is only used in some cases where a provider offers a special URL for authorization that's specifically for sign-in-with-provider functionality. For example, Twitter offers a special URL for authentication that differs from authorization in that it won't force the user to explicitly authorize if a previous authorization was already given. Even if you don't provide that, the OAuth2Template will fall back and use the authorization URL instead.

    But for client authentication, which is what you're doing here, neither the authentication nor authorization URLs are used. it's the access token URL that's in play.

    From the log messages it's saying that the client ID wasn't provided. Can you confirm that there *is* a client ID being passed into the constructor? It may not be null (there are assertions to guarantee that), but if it's empty then that's just as big of a problem. (Maybe I should make those assertions stronger to enforce non-blank and non-null values.)
    Craig Walls
    Spring Social Project Lead

  9. #9

    Default

    Yes, I can confirm, clientId is definitely gets correct value and initialized in constructor:

    In constructor's code :
    Code:
    this.clientSecret = clientSecret;
    String clientInfo = "?client_id=" + formEncode(clientId);
    this.authorizeUrl = authorizeUrl + clientInfo; // value here = https://www.facebook.com/dialog/oauth?client_id=5138XXX786XXX92
    if (authenticateUrl != null) {
        this.authenticateUrl = authenticateUrl + clientInfo;
    } else {
        this.authenticateUrl = null;
    }
    but on the line:
    if (authenticateUrl != null) {...
    it goes to ELSE statement and makes: this.authenticateUrl = null;

    That's why I'm asking about it...
    Best regards.

  10. #10
    Join Date
    Aug 2004
    Posts
    1,072

    Default

    Again, it's totally fine that the authenticateUrl is null. It is almost always null for most providers. During the authorization code flow in ProviderSignInController, it will use it if it's not null, but will use the authorizationUrl if the authenticationUrl is null. I do not believe that this has anything to do with your problem because that URL is not used for client authorization.

    Here's your problem, though: The client_id parameter is not being sent in access token request. The quick fix is to do this because you call authenticateClient():

    Code:
    oauth.setUseParametersForClientAuthentication(true);
    That should make things work. For the lengthy explanation of why, read on...

    Per the latest (and now final) drafts of the OAuth2 specification, client credentials *should* be sent in an HTTP Basic authentication header and *not* in query parameters. Older drafts of the specification said that they could be sent in query parameters. Facebook still wants them in query parameters.

    By default, OAuth2Template will do what the latest/final draft specifies and sends them in an HTTP Basic header. But that doesn't work for Facebook (or most providers, actually, because most providers haven't updated their implementation to the latest spec). But if you set useParametersForClientAuthentication to true, then the client credentials will be sent in query parameters and not in an HTTP Basic header; thus making Facebook happy.
    Craig Walls
    Spring Social Project Lead

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •