Skip to content

journal 2020 09 08: A "bug" in `oauthenticated`

Eason Chen edited this page Sep 8, 2020 · 4 revisions

I was moving along, super slowly but super surely, to make an OAuth-signed request to Twitter. The example endpoint I chose was

However after a lot of failed attempts and lots of print debugging, I realised that the oauthenticated library was for some reason not outputting the access token in the oauth_token component of the Authorization header of my intended signed request. This component is supposed to hold the access token, as discussed in Twitter's guiding documentation. It also makes sense from an OAuth conceptual point-of-view: you can't just omit a part of the signature base string and still hope the signature checks out.

Since my request is missing that OAuth param, of course it isn't going to work --- but how come?? Haskell libraries are almost never broken like this, so I was almost immediately furious...

... until I found this oauthParams function in oauthenticated source code that has a comment that exactly addresses my question:

oauthParams :: Oa ty -> Server -> H.Query
oauthParams (Oa {..}) (Server {..}) =
  let

    OaPin {..} = pin

    infix 8 -:
    s -: v = (s, H.toQueryValue v)

    -- **NOTE** dfithian: It worked for my use case to move oauth_token into these params. From the
    -- PR:
    --
    -- I presume one very controversial thing I did was to move `oauth_token` into `workflowParams`.
    -- I came to this conclusion by skimming through the [RFC](https://tools.ietf.org/html/rfc5849)
    -- and deciding that since I only ever saw `oauth_token` in conjunction with either
    -- `oauth_callback` or `oauth_verifier` that they should go together. I'd be perfectly happy to
    -- instead pass in some function of the settings telling it whether or not to include
    -- `oauth_token` for a given request. Whatever the conclusion, the service I'm integrating to
    -- specifically does NOT want the `oauth_token` so that was the motivation.
    workflowParams Standard = []
    workflowParams (TemporaryTokenRequest callback) =
      [ "oauth_callback" -: callback
      , "oauth_token" -: (getResourceTokenDef credentials ^. key) ]
    workflowParams (PermanentTokenRequest verifier) =
      [ "oauth_verifier" -: verifier
      , "oauth_token" -: (getResourceTokenDef credentials ^. key) ]

  in

    [ "oauth_version"          -: oAuthVersion
    , "oauth_consumer_key"     -: (credentials ^. clientToken . key)
    , "oauth_signature_method" -: signatureMethod
    , "oauth_timestamp"        -: timestamp
    , "oauth_nonce"            -: nonce
    ] ++ workflowParams workflow

Oh well! Let's say, I definitely laughed to myself at the tacit understanding with another Haskell developer I've never met.

Looks like I'll have to copy-paste patch it in order to get it to do what I want.

Update: I found a hack, and it worked first-time. LOL!

diff --git a/src/TwitAnalysis/TwitterApiCallDemo.hs b/src/TwitAnalysis/TwitterApiCallDemo.hs
index 3e6a27c..4e12137 100644
--- a/src/TwitAnalysis/TwitterApiCallDemo.hs
+++ b/src/TwitAnalysis/TwitterApiCallDemo.hs
@@ -55,7 +55,16 @@ fetchCurrentUser Env {envHttpMan} cred srv = do
           , ("include_email", Just "false")
           ]
           initReq
-  signedReq <- OAuthSigning.oauth cred srv unsignedReq
+  oax <- OAuthParams.freshOa cred
+  -- Hack around a difference-in-understanding compared to the author of oauthenticated.
+  -- The `oauth_token` component would be omitted from the `Authorization` header otherwise.
+  -- See journal for back-story:
+  --  - https://github.com/easoncxz/twitanalysis/wiki/journal-2020-09-08:-A-%22bug%22-in-%60oauthenticated%60
+  let hackedOax :: OAuthParams.Oa Permanent
+      hackedOax =
+        oax {OAuthParams.workflow = OAuthParams.PermanentTokenRequest "bogus"}
+  putStrLn $ "Here are the generated OAuth params: " ++ show hackedOax
+  let signedReq = OAuthSigning.sign hackedOax srv unsignedReq
   putStrLn $ "About to make this request: " ++ show signedReq
   let headers = (HC.requestHeaders signedReq)
   putStrLn $ "In particular, the headers are: " ++ show headers

And voilà, my Twitter user, presented in pretty-printed JSON as a <pre> element:

image

Clone this wiki locally