diff --git a/Web/Authenticate/Facebook.hs b/Web/Authenticate/Facebook.hs
new file mode 100644
--- /dev/null
+++ b/Web/Authenticate/Facebook.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE FlexibleContexts #-}
+module Web.Authenticate.Facebook where
+
+import Network.HTTP.Wget
+import Data.List (intercalate)
+import Data.Object
+import Data.Object.Json
+import Data.ByteString.Char8 (pack)
+
+data Facebook = Facebook
+    { facebookClientId :: String
+    , facebookClientSecret :: String
+    , facebookRedirectUri :: String
+    }
+    deriving (Show, Eq, Read)
+
+newtype AccessToken = AccessToken { unAccessToken :: String }
+    deriving (Show, Eq, Read)
+
+getForwardUrl :: Facebook -> [String] -> String
+getForwardUrl fb perms = concat
+    [ "https://graph.facebook.com/oauth/authorize?client_id="
+    , facebookClientId fb -- FIXME escape
+    , "&redirect_uri="
+    , facebookRedirectUri fb -- FIXME escape
+    , if null perms
+        then ""
+        else "&scope=" ++ intercalate "," perms
+    ]
+
+accessTokenUrl :: Facebook -> String -> String
+accessTokenUrl fb code = concat
+    [ "https://graph.facebook.com/oauth/access_token?client_id="
+    , facebookClientId fb
+    , "&redirect_uri="
+    , facebookRedirectUri fb
+    , "&client_secret="
+    , facebookClientSecret fb
+    , "&code="
+    , code
+    ]
+
+getAccessToken :: Facebook -> String -> IO AccessToken
+getAccessToken fb code = do
+    let url = accessTokenUrl fb code
+    b <- wget url [] []
+    let (front, back) = splitAt 13 b
+    case front of
+        "access_token=" -> return $ AccessToken back
+        _ -> error $ "Invalid facebook response: " ++ back
+
+graphUrl :: AccessToken -> String -> String
+graphUrl (AccessToken s) func = concat
+    [ "https://graph.facebook.com/"
+    , func
+    , "?access_token="
+    , s
+    ]
+
+getGraphData :: AccessToken -> String -> IO StringObject
+getGraphData at func = do
+    let url = graphUrl at func
+    b <- wget url [] []
+    decode $ pack b
diff --git a/Web/Authenticate/OpenId.hs b/Web/Authenticate/OpenId.hs
--- a/Web/Authenticate/OpenId.hs
+++ b/Web/Authenticate/OpenId.hs
@@ -26,11 +26,7 @@
 import Network.HTTP.Wget
 import Text.HTML.TagSoup
 import Numeric (showHex)
-#if MIN_VERSION_transformers(0,2,0)
 import "transformers" Control.Monad.IO.Class
-#else
-import "transformers" Control.Monad.Trans
-#endif
 import Data.Data
 import Control.Failure hiding (Error)
 import Control.Exception
diff --git a/Web/Authenticate/Rpxnow.hs b/Web/Authenticate/Rpxnow.hs
--- a/Web/Authenticate/Rpxnow.hs
+++ b/Web/Authenticate/Rpxnow.hs
@@ -22,11 +22,7 @@
 import Data.Object
 import Data.Object.Json
 import Network.HTTP.Wget
-#if MIN_VERSION_transformers(0,2,0)
 import "transformers" Control.Monad.IO.Class
-#else
-import "transformers" Control.Monad.Trans
-#endif
 import Control.Failure
 import Data.Maybe
 import Web.Authenticate.OpenId (AuthenticateException (..))
diff --git a/authenticate.cabal b/authenticate.cabal
--- a/authenticate.cabal
+++ b/authenticate.cabal
@@ -1,5 +1,5 @@
 name:            authenticate
-version:         0.6.2
+version:         0.6.3
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -23,5 +23,6 @@
                      transformers >= 0.1 && < 0.3,
                      bytestring >= 0.9 && < 0.10
     exposed-modules: Web.Authenticate.Rpxnow,
-                     Web.Authenticate.OpenId
+                     Web.Authenticate.OpenId,
+                     Web.Authenticate.Facebook
     ghc-options:     -Wall -fno-warn-orphans
