Ben Biddington

Whatever it is, it's not about "coding"

Posts Tagged ‘oauth

Facebook Graph API — getting access tokens

with 73 comments

As described in the documentation it’s a fairly easy process — and it does not require any signatures.

For example, I have an application with an id 116122545078207, and I am using the URL of this blog (https://benbiddington.wordpress.com) to collect request tokens.

[update, 2010-04-29]

If ever there was a lesson to read specification and documentation carefully, this is it. Thanks to comments from Joshua Inkenbrandt, Alex and Gene Leybzon I realise why my examples don’t work as expected: I have been trying to use a mixture of web server and client_cred authentication flow.

As Gene rightly points out, I should have been using user_agent.

User-Agent Flow (with a web browser)

Following the instructions as specified in section 3.5.1.1., Client Requests Authorization, of the specification, this is a one-step process:

Open this in a browser:

https://graph.facebook.com/oauth/authorize?
    type=user_agent&
    client_id=116122545078207&
    redirect_uri=http%3A%2F%2Fbenbiddington.wordpress.com&
    scope=user_photos,email,user_birthday,user_online_presence

Note: there are several options for scope. These are called extended permissions.

Note: unless you specify offline_access, your tokens will expire as soon as the user signs out of facebook.

Note: client_secret is not supplied:

[3.5.1.  User-Agent Flow] This user-agent flow does not utilize the client secret since the client executables reside on the end user’s computer or device which makes the client secret accessible and exploitable.

You’ll be redirected to:

https://benbiddington.wordpress.com/#access_token=
    116122545078207|
    2.1vGZASUSFMHeMVgQ_9P60Q__.3600.1272535200-500880518|
    QXlU1XfJR1mMagHLPtaMjJzFZp4.

And you have your access token, you can go ahead and use it:

https://graph.facebook.com/me?access_token=
    116122545078207|
    2.1vGZASUSFMHeMVgQ_9P60Q__.3600.1272535200-500880518|
    QXlU1XfJR1mMagHLPtaMjJzFZp4.

According to section 3.5.1. Client Requests Authorization, because we have not supplied the optional secret_type:

secret_type
    OPTIONAL. The access token secret type as described by Section 5.3.
    If omitted, the authorization server will issue a bearer token
    (an access token without a matching secret) as described by Section 5.2.

we have been issued a bearer token.

I think this refers to OAuth 1.0-style authentication using token secret. You’d only need one of those if you were requiring signed requests. This seems to contradict the part above about storing client secret on user agent.

Refreshing tokens

Section 3.5.1 describes that the access token may be delivered with an optional refresh_token fragment. On expiry, this token can be exchanged at the for a new access token. No refresh token is supplied by the Facebook API under User-Agent flow, meaning you’ll have to ask users to sign in again.

Using access tokens

Tokens with no session part

In some cases, like when using 3.7.1.  Client Credentials Flow, you’re issued a token with a missing session part.

Instead of this:

    116122545078207|
    2.1vGZASUSFMHeMVgQ_9P60Q__.3600.1272535200-500880518|
    EyWJJYqrdgQgV1bfueck320z7MM.

you get this:

116122545078207|EyWJJYqrdgQgV1bfueck320z7MM.

These do work in some cases, but are rejected by some resources, for example:

https://graph.facebook.com/me?access_token=116122545078207|EyWJJYqrdgQgV1bfueck320z7MM.

returns  error:

{
   "error": {
      "type": "QueryParseException",
      "message": "An active access token must be used to query information about the current user."
   }
}

this is the same error you get when you request the same resource without supplying a token at all:

http://graph.facebook.com/me

Note that these tokens do work against real resource identifer, i.e., without the me alias. For example, here I can use it against me (benbiddington).

https://graph.facebook.com/benbiddington?access_token=116122545078207|EyWJJYqrdgQgV1bfueck320z7MM.

So the me alias only works in the case where we have a full token — the session part is required.

These tokens also work for accessing your insights (see analytics section):

https://graph.facebook.com/app_id/insights?access_token=116122545078207|EyWJJYqrdgQgV1bfueck320z7MM.

This is described in section 3.7.  Autonomous Client Flows:

Autonomous client flows are used to grant client access to protected resources controlled by the client (i.e. the client is the resource owner). For example, these flows are useful when a service provides both client-specific resources in addition to end user resources.

And more specifially, the Client Credentials Flow is described  in section 3.7.1:

The client credentials flow is used when the client acts autonomously without acting on behalf of a separate resource owner. The client secret is assumed to be high-entropy since it is not designed to be memorize by an end user.

Where a client is:

An HTTP client capable of making authenticated requests for protected resources using the OAuth protocol. [This is third-party application that wants to access a resource owner’s Facebook account.]

And a resource owner:

An entity capable of granting access to a protected resource. [This is the user who owns the Facebook account.]

[TBD: So what?]

Tokens, sessions and that

You can see more information about authentication flow by using a bogus redirect_uri, i.e., one that does not match the Connect URL setting in your application, e.g.:

https://graph.facebook.com/oauth/authorize?
    client_id=116122545078207&
    redirect_uri=http%3A%2F%2Flocalhost&
    scope=user_photos

Executing this gives error:

{
   "error": {
      "type": "OAuthException",
      "message": "Invalid redirect_uri: The Facebook Connect cross-domain
          receiver URL (http://localhost) must have the application's
          Connect URL (https://benbiddington.wordpress.com) as a prefix.
          You can configure the Connect URL in the Application Settings Editor."
   }
}

But there is some information in the query string, that when decoded looks like this:

https://graph.facebook.com/oauth/authorize_success?
    client_id=116122545078207&
    redirect_uri=http://localhost&
    scope=user_photos&
    type=web_server&
    perms=user_photos&
    selected_profiles=500880518&
    session={
        "session_key":"2.vHAZRg0Ac4Dtzm2xiVwXoA__.3600.1272286800-500880518",
        "uid":500880518,
        "expires":1272286800,
        "secret":"vHAZRg0Ac4Dtzm2xiVwXoA__",
        "sig":"7a6fc887240884de883a21e2a2aec3e0"
    }

That session_key:

2.vHAZRg0Ac4Dtzm2xiVwXoA__.3600.1272286800-500880518

looks familiar, it’s the same as the code parameter used in web server authentication flow (Section 3.5.2), and it’s the same pattern as the second segment of an access token.

2.{secret}.3600.{expires_at_seconds_after_epoch}-{user_id}

Where are my extended permissions?

It appears there is some problem with authorizing extended permissions.

For example, when I use the link in step (1) up there, I am prompted with the following screen:

That looks like the set I asked for, and so I select Allow.

But when I then inspect the extended permissions in my Application settings, all I see is this:

For some reason the only extra permission I have is email. And actually, did I even ask for Publish recent activity?

What is wrong here?

Troubleshooting

I can’t see my application in my Application settings screen

Make sure to choose Authorised from the show list on the Application settings screen.

The default view is Recently used which — certainly in my case — does not produce my application.

How do I know what permissions my application has?

Once you find the application in your Application settings list, press Edit settings and then select the Additional Permissions tab on the resultant dialog.

How do I de-authorise an application?

From your Application settings list, press the “x” button the right end of the row next to Application Profile link.

My access tokens only seem valid while a user is signed-in to facebook

You need to request offline_access permissions, e,g,:

https://graph.facebook.com/oauth/authorize?
    type=user_agent&
    client_id=116122545078207&
    redirect_uri=http%3A%2F%2Fbenbiddington.wordpress.com&
    scope=user_photos,email,user_birthday,user_online_presence,offline_access

otherwise your access tokens will expire as soon as the user signs out and you’ll get (at least with client):

{
    "error": {
        "type": "OAuthException",
        "message": "Error processing access token."
    }
}

References

Advertisements

Written by benbiddington

23 April, 2010 at 13:37

Posted in development

Tagged with , , , ,

Scala introduction — writing an OAuth library

leave a comment »

I started out intending to write some scala examples against the twitter API, however I soon discovered I needed OAuth first. Given that I use OAuth all the time at work I figured I could probably do with learning about it first-hand, while learning scala.

org.junit.rules._

I chose to test drive it with JUnit 4.7 and NetBeans.

NetBeans works almost immediately with scala, and has support for project templates etc — even scala JUnit fixtures.

UPDATE (2010-04-27) I have since discovered IntelliJ to be much better, and there is now a free community edition. IntelliJ supports scala without any fiddling around.

JUnit mostly works, though rules don’t and neither do some matchers. Even though rules don’t work, I have included it anyway because I have the t-shirt.

You can find the project on github.

Important abstractions

  1. SignatureBaseString.
    1. Characterized by three ampersand-separated segments: verb, uri, parameters.
    2. URL Encoding must conform to RFC 3986, and the following characters should are consider unreserved so should not be encoded:
      ALPHA, DIGIT, ‘-‘, ‘.’, ‘_’, ‘~’
  2. Signature.
    1. Signature is a keyed-Hash Message Authentication Code (HMAC).
    2. Consumer secret required part of HMAC secret key.
    3. Token secret is optionally included in HMAC secret key:
      (consumer_secret, token_secret) => uri_encoded_consumer_secret&[uri_encoded_token_secret]
  3. OAuthCredential. Represents the secret key(s) used to create the HMAC signature. OAuth requires a consumer credential, and optionally a token credential, representing the end user.

Now that these core concepts are complete, I am working on high-level policy, like classes for generating signed URLs and authorization headers.

Notes

JUnit — expecting exceptions in scala

Assuming JUnit 4.x, a test can expect an exception using the test annotation:

Java:

@Test(expected=IllegalArgumentException.class)
    public void ExampleThrowsException(){
        throw new IllegalArgumentException();
    }

This needs to be modified for scala:

Scala:

@Test { val expected=classOf[IllegalArgumentException] }
    def ExampleThrowsException {
        throw new IllegalArgumentException
    }

The reason for it is outlined here in the Java annotations section on named parameters.

Here is the documentation for scala annotations. Seealso: the documentation for scala 2.7.3 (includes dbc).

Closures and return

The return statement immediately returns from the current method, even if you’re within a closure. Omit return in this case — return is optional anyway.

When to use semicolon line terminator

Never — apart from:

  • When a method returns Unit (equivalent to void) and you aren’t using return keyword. [TBD: Add example].

How to use blocks

var count = 1
times(2) { println("Printed " + count + " times")}
protected def times(count : Int)(block : => Unit) = {
    1.to(count).foreach((_) => block)
}

Seealso: some executable examples on github

References

ALPHA, DIGIT, '-', '.', '_', '~'

Written by benbiddington

18 September, 2009 at 13:37

Posted in development

Tagged with , , , , , , , ,