Giter Site home page Giter Site logo

hoauth2's Introduction

hoauth2's People

Contributors

bartmassey avatar cbeav avatar drpowell avatar freiric avatar freizl avatar gertcuykens avatar guaraqe avatar hw202207 avatar iand675 avatar jwoudenberg avatar karknu avatar magicloud avatar master-q avatar meteficha avatar mitchellwrosen avatar nakaji-dayo avatar natdash avatar nightkr avatar nkpart avatar ocheron avatar pbrisbin avatar puffnfresh avatar reactormonk avatar reneklacan avatar tazjin avatar teh avatar willsewell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hoauth2's Issues

Seems like there is no "expires_in" in access token?

Per Google document, there are 4 attributes returned. hoauth2 only has the first two.

access_token    The token that can be sent to a Google API.
refresh_token   A token that may be used to obtain a new access token, included by default for installed applications. Refresh tokens are valid until the user revokes access.
expires_in  The remaining lifetime of the access token.
token_type  Identifies the type of token returned. Currently, this field always has the value Bearer.

Upgrade is not compatible with snap

After bump conduit depends (issue 2), it failed to work with snap thus broken snaplet-oauth.

  • work around for snaplet-oauth is to use version-0.2.2

Deprecate doFlexiblePostRequest

  • it's added because of stackexchange access token response is query string but turns out it does support json.
  • json response shall be standard.
  • mark it as deprecated.

OAuth2 JWT implementation

Feature request of a haskell implementation of OAuth2 JWT

https://developers.google.com/accounts/docs/OAuth2ServiceAccount

This is my bash version

jwt1=`echo -n '{"alg":"RS256","typ":"JWT"}' | openssl base64 -e`

jwt2=`echo -n '{\
"iss":"522156758812-u8hj8dhnk5br3vnpqqvuscievhbnl0gg@developer.gserviceaccount.com",\
"scope":"https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/datastore",\
"aud":"https://accounts.google.com/o/oauth2/token",\
"exp":'$(($(date +%s)+3600))',\
"iat":'$(date +%s)'}' | openssl base64 -e`

jwt3=`echo -n "$jwt1.$jwt2" | tr -d '\n' | tr -d '=' | tr '/+' '_-'`

jwt4=`echo -n "$jwt3" | openssl sha -sha256 -sign google.p12 | openssl base64 -e`

jwt5=`echo -n "$jwt4" | tr -d '\n' | tr -d '=' | tr '/+' '_-'`

curl -H "Content-type: application/x-www-form-urlencoded" -X POST "https://accounts.google.com/o/oauth2/token" -d \
"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=$jwt3.$jwt5"

Testing it on google datastore

curl -X GET "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=$1"
curl -X GET "https://www.googleapis.com/oauth2/v2/userinfo?access_token=$1"
curl -H "Content-type: application/json" -H "Authorization:  Bearer $1" -X POST "https://www.googleapis.com/datastore/v1beta1/datasets/gcl-11/blindWrite" -d \
'{
 "mutation": {
  "upsert": [
   {
    "key": {
     "path": [
      {
       "kind": "person",
       "name": "gert"
      }
     ]
    }
   }
  ]
 }
}'

Can't decode valid JSON from Azure AD

Hi, I am having an issue similar to #47, and I am hoping you can help. I started off with the yesod-auth-oauth2 plugin, but I have had to do some "hacking" and I am basically writing my own Yesod plugin at this point. I can confirm that the end point produces valid JSON:

{
  "token_type": "Bearer",
  "scope": "User.Read",
  "expires_in": "3599",
  "ext_expires_in": "0",
  "expires_on": "1511997544",
  "not_before": "1511993644",
  "resource": "223079d7-da8a-49da-b8c5-2394bb50c326",
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyIsImtpZCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyJ9.eyJhdWQiOiIyMjMwNzlkNy1kYThhLTQ5ZGEtYjhjNS0yMzk0YmI1MGMzMjYiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC82ZmM1NGIwZS1mOTIwLTRiYmMtYWZmMC01NDliN2IzMjIxMjYvIiwiaWF0IjoxNTExOTkzNjQ0LCJuYmYiOjE1MTE5OTM2NDQsImV4cCI6MTUxMTk5NzU0NCwiYWNyIjoiMSIsImFpbyI6IlkyTmdZSWo2VSs3RFdMMDRvaUNPNGVDZHRBdVpYZkd1Wi90OFREVm1zbnl6RTRob1d3SUEiLCJhbXIiOlsicHdkIl0sImFwcGlkIjoiMjIzMDc5ZDctZGE4YS00OWRhLWI4YzUtMjM5NGJiNTBjMzI2IiwiYXBwaWRhY3IiOiIxIiwiZmFtaWx5X25hbWUiOiJTb2xsYSIsImdpdmVuX25hbWUiOiJBbGV4YW5kZXIiLCJpcGFkZHIiOiIxNzMuMTY0LjgwLjIwMSIsIm5hbWUiOiJBbGV4YW5kZXIgU29sbGEiLCJvaWQiOiI3MzM5OWE3ZC03NzVhLTQ1NjEtYTFiYi0yZGUzN2IzZDk0ZmQiLCJzY3AiOiJVc2VyLlJlYWQiLCJzdWIiOiJudElGT1BBM0VUZUtkQjlneVVCYlZZZ2JtU19FOUliUlhwQzNFZ3NyZXhnIiwidGlkIjoiNmZjNTRiMGUtZjkyMC00YmJjLWFmZjAtNTQ5YjdiMzIyMTI2IiwidW5pcXVlX25hbWUiOiJvcHNAb2xkbWlsbGNlbnRlci5vcmciLCJ1cG4iOiJvcHNAb2xkbWlsbGNlbnRlci5vcmciLCJ1dGkiOiJyX2Y3TTRIQU5rZXhUdzdJb3NVUEFBIiwidmVyIjoiMS4wIn0.WYWegS4TXPacvpw0KYOcAsb2bk630ZToih1Lc-HYaIufx1ckx5eFnXsmvnJ1xJdLyMZhKWqbXnXbsZX448bzaoiDH8FHjLi7gBefd5dIT82kcITm30zqP6vh_a4nB_HJlNIbWKVHPR6a_2w8RPfvSq5C4gKqKiVgaIkCFGlgxsEfDqRgxpdu1AP556o_M-MqOQQdVxdr8yXNqqNTtHnx2MXPRR0i4edwacBeHkQyriwdkIjrpPgDSRNQ7TH3kOGhx21pyn8m9X46W8FLVReY7kxa5XLZ7XAW03dnS05lXww6ugkzv0dCJIghnZfLNgs5kEHykSNaYTOdQMcYf0vzAw",
  "refresh_token": "AQABAAAAAABHh4kmS_aKT5XrjzxRAtHzXJ3BbzWYPG4vu9K044Ix9IHWke23NBsBd5RGdJ9p-htS0NdL6AUYxuHoWg-BFQvzntMF0gW_hzPOzR2dvsGbaK9AnkWHYjC0noT3-jNBtxsU6FA2OdsYRlAwCp0uTyULKZhVySllqSuG4eOWaKS23t55ZZzl3oZFYnafhPA-J13zG4ZKXCgKR99EMMnJ2N6d1YhMP7jqw7WT-W7oZH4fj1Czt1XIND130JZvD0fiEp8sK--my_5NuFlVFX0Mr6tk0PEJtWzpwP9eHfhZqje1Uh1sdm4QBIgSvyHuP7-usYdH9dTFXTeJ9nxcL6bUuDLIloG2j-mS1RlYKZjzZZmBcVHEfJ6b5KgJ1thr2rp8NTe_VwCFgdnFhoMrIsh4rKrL7KGP7-W51lwBnLjsotz-G8NLzzH7FEfpqN9MUDsaAZhyUUjyKykRE7FLLn5_GLLjws8yHyRNmZV630dPWetz3tSQqw3zivfzt6ams2VrLqmCpETUWNMoc4fz4xU0-q_QsrLVpNcDL4Z3Her_HMaOE6_PFLjh7a2S2GN_d8h_9IpKm9FQRez1nuwnP0CBN_J6FNKl9SNVaLRXkZD7rS7wANPhTYRpH3Z0fIrwzeMA7YdLoqml3_u_-LxaCxdWeFN06akRMS7gfwZIAkp5OTv_KavAjQDiHkAfoFPA3smWVVxJhe5GzdF3N7RMAF0JzEFgaVK9HaW1Lw3BDZkZ3uM5fKtwsMzajyDX39tgwg2BF5LbCLZ6aFNft_7KTJun2YjqMWkgREiwHLe8api3Uy5ftCAA",
  "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIyMjMwNzlkNy1kYThhLTQ5ZGEtYjhjNS0yMzk0YmI1MGMzMjYiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC82ZmM1NGIwZS1mOTIwLTRiYmMtYWZmMC01NDliN2IzMjIxMjYvIiwiaWF0IjoxNTExOTkzNjQ0LCJuYmYiOjE1MTE5OTM2NDQsImV4cCI6MTUxMTk5NzU0NCwiYW1yIjpbInB3ZCJdLCJmYW1pbHlfbmFtZSI6IlNvbGxhIiwiZ2l2ZW5fbmFtZSI6IkFsZXhhbmRlciIsImlwYWRkciI6IjE3My4xNjQuODAuMjAxIiwibmFtZSI6IkFsZXhhbmRlciBTb2xsYSIsIm9pZCI6IjczMzk5YTdkLTc3NWEtNDU2MS1hMWJiLTJkZTM3YjNkOTRmZCIsInN1YiI6Im50SUZPUEEzRVRlS2RCOWd5VUJiVllnYm1TX0U5SWJSWHBDM0Vnc3JleGciLCJ0aWQiOiI2ZmM1NGIwZS1mOTIwLTRiYmMtYWZmMC01NDliN2IzMjIxMjYiLCJ1bmlxdWVfbmFtZSI6Im9wc0BvbGRtaWxsY2VudGVyLm9yZyIsInVwbiI6Im9wc0BvbGRtaWxsY2VudGVyLm9yZyIsInZlciI6IjEuMCJ9."
}

However, for some reason, the code I have written (following hoauth2 and yesod-auth-oauth2):

getAccessToken :: Manager -> OAuth2 -> ExchangeToken -> IO (OAuth2Result Errors OAuth2Token)
getAccessToken manager oa code = do

  let (uri, defaultBody) = accessTokenUrl oa code
  let body = defaultBody <> [ ("client_id", TE.encodeUtf8 . oauthClientId $ oa )
                            , ("client_secret", TE.encodeUtf8 . oauthClientSecret $ oa)
                            , ("resource", TE.encodeUtf8 . oauthClientId $ oa)
                                            ]

  (response :: OAuth2Result Errors OAuth2Token) <- (parseResponseJSON . handleResponse)
                                                      <$> performOAuth2PostRequest manager oa uri body
  putStrLn "Performing OAuth2 Post Request..."
  case response of
    Left e -> putStrLn . Text.pack . show $ e
    Right token -> putStrLn . Text.pack . show $ token

  return $ error "Need to finish processing the AccessToken"

performOAuth2PostRequest :: Manager -> OAuth2 -> URI -> PostBody -> IO (Response Lazy.ByteString)
performOAuth2PostRequest manager oa uri body  = do
  defaultReq <- uriToRequest uri

  let addBasicAuth = applyBasicAuth (TE.encodeUtf8 . oauthClientId $ oa)
                                    (TE.encodeUtf8 . oauthClientSecret $ oa)

  let req = (addBasicAuth . updateRequestHeaders Nothing) defaultReq

  HTTP.httpLbs (urlEncodedBody body req) manager

produces an error I don't understand. (Notice that the error is coming from the Left e case):

OAuth2Error {error = Left "Decode error", errorDescription = Just "Error: Error in $: key \"error\" not present\n Original Response:\n\"{\\\"token_type\\\":\\\"Bearer\\\",\\\"scope\\\":\\\"User.Read\\\",\\\"expires_in\\\":\\\"3599\\\",\\\"ext_expires_in\\\":\\\"0\\\",\\\"expires_on\\\":\\\"1512000084\\\",\\\"not_before\\\":\\\"1511996184\\\",\\\"resource\\\":\\\"223079d7-da8a-49da-b8c5-2394bb50c326\\\",\\\"access_token\\\":\\\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyIsImtpZCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyJ9.eyJhdWQiOiIyMjMwNzlkNy1kYThhLTQ5ZGEtYjhjNS0yMzk0YmI1MGMzMjYiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC82ZmM1NGIwZS1mOTIwLTRiYmMtYWZmMC01NDliN2IzMjIxMjYvIiwiaWF0IjoxNTExOTk2MTg0LCJuYmYiOjE1MTE5OTYxODQsImV4cCI6MTUxMjAwMDA4NCwiYWNyIjoiMSIsImFpbyI6IlkyTUFndlgxVzV5dHprbmR6dktOVzNEbXpPNmNyZHFpYWU2Q3Izc2taRDFhZGFhdUJRQT0iLCJhbXIiOlsicHdkIl0sImFwcGlkIjoiMjIzMDc5ZDctZGE4YS00OWRhLWI4YzUtMjM5NGJiNTBjMzI2IiwiYXBwaWRhY3IiOiIxIiwiZmFtaWx5X25hbWUiOiJTb2xsYSIsImdpdmVuX25hbWUiOiJBbGV4YW5kZXIiLCJpcGFkZHIiOiIxNzMuMTY0LjgwLjIwMSIsIm5hbWUiOiJBbGV4YW5kZXIgU29sbGEiLCJvaWQiOiI3MzM5OWE3ZC03NzVhLTQ1NjEtYTFiYi0yZGUzN2IzZDk0ZmQiLCJzY3AiOiJVc2VyLlJlYWQiLCJzdWIiOiJudElGT1BBM0VUZUtkQjlneVVCYlZZZ2JtU19FOUliUlhwQzNFZ3NyZXhnIiwidGlkIjoiNmZjNTRiMGUtZjkyMC00YmJjLWFmZjAtNTQ5YjdiMzIyMTI2IiwidW5pcXVlX25hbWUiOiJvcHNAb2xkbWlsbGNlbnRlci5vcmciLCJ1cG4iOiJvcHNAb2xkbWlsbGNlbnRlci5vcmciLCJ1dGkiOiJPMUhRSmJXUWRFQ0VDOEVYVEZnUUFBIiwidmVyIjoiMS4wIn0.gU5dWrDvxkDdWcFURZHB3KJrJH0pWvulX-F1tGACiDU3MhWfcgMbomTM_TK3308cvBfBmmZD0lcgVX1BzErG5mtkcQ8edlSzidzwfLdRm-kLzA-obqOB1pFPgE2uPEsUCj6btcp3KdvNsqKxK5Ci2jY44RZOscn6RpwP18lC-qQokVDMvmAAg8tKCbSy2Km046UQSZOA1kShlnFKox0Pum12Ef-6KiCLjQ88E0xUWPKNyhbVUrl3MX_4OzIBjbd25rakzFejPLxdUnJbh0AbZD5xMNBSsPPxLsg97nvDGI6EPbChFpSvGGH-gS133s0666L4c7W55BZOHhlffh9WdQ\\\",\\\"refresh_token\\\":\\\"AQABAAAAAABHh4kmS_aKT5XrjzxRAtHzRbW1mWZjN0JXaJb5-m0xsf_PdQJrcS4NbMbypLzRbCeMpzjEc0YovwWzLLPNAqsdsRzAqKhHZX-jAz9hZeuRWMPvpakYqVgcjzBrm42_qPbcm1f_nauxLUnj13CH4pVUb4qQXBQ0C9_iXqgKkqsPecMCQZfkQth5OTZk2_A39L1yM4_6Hrgjdub-kxhDdqx5vPXE36cwdKFWt1qMjUfDI4vFBPt3C-wQYYT-AFcBFtZQbzxiCowYHEcds28550PrDdX_mDvUOuTkUpiT_J0Ec4dBxFHE4gbMNqG0v1F4oiNoOAcnwDFhXoqAOR1wfpwLhnAgRWHSWl-UqKe72wUAJdRCc0o0V6OD0-lr7CPNqcFp_uJHeRd3SzEKt3HRuPZPTi4duSBF1PoNwCT_qdOqBQd0oMP8j2kqYKhAhqEJo7QFID6ohrXI-m6kv-_n_dzC7zWFVCj7N6pwAplVzudjjYTYvldo-lMFYwA26v3axRua3WlfIPQ9Fw883q7tKDfrK0hJ4zIRtqf2CSZULiL6MbF-m_f_iu2LPtzPc1xuZtcYCvCK64EGYrlAP0g1PZ1TpHSvQOnUXNotsxtN9p8bkfVIfduOU7X1AierVgzQMT0h9uHsuYoHFxcZLe5zbZbQrVsYrJoqCCGnv8S6PWSawD5_M8crNyuqrDtTMxADK-kkcu1_Egjzb4IQuOaqIjizFE-oZZjq0S_lGNEOKleqynaVD3vmhxOmGkwl8B8LkJ55K-bjIioOnFBESA7u7P9zz3X_jCIG0khqkQSr2mxlhCAA\\\",\\\"id_token\\\":\\\"eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIyMjMwNzlkNy1kYThhLTQ5ZGEtYjhjNS0yMzk0YmI1MGMzMjYiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC82ZmM1NGIwZS1mOTIwLTRiYmMtYWZmMC01NDliN2IzMjIxMjYvIiwiaWF0IjoxNTExOTk2MTg0LCJuYmYiOjE1MTE5OTYxODQsImV4cCI6MTUxMjAwMDA4NCwiYW1yIjpbInB3ZCJdLCJmYW1pbHlfbmFtZSI6IlNvbGxhIiwiZ2l2ZW5fbmFtZSI6IkFsZXhhbmRlciIsImlwYWRkciI6IjE3My4xNjQuODAuMjAxIiwibmFtZSI6IkFsZXhhbmRlciBTb2xsYSIsIm9pZCI6IjczMzk5YTdkLTc3NWEtNDU2MS1hMWJiLTJkZTM3YjNkOTRmZCIsInN1YiI6Im50SUZPUEEzRVRlS2RCOWd5VUJiVllnYm1TX0U5SWJSWHBDM0Vnc3JleGciLCJ0aWQiOiI2ZmM1NGIwZS1mOTIwLTRiYmMtYWZmMC01NDliN2IzMjIxMjYiLCJ1bmlxdWVfbmFtZSI6Im9wc0BvbGRtaWxsY2VudGVyLm9yZyIsInVwbiI6Im9wc0BvbGRtaWxsY2VudGVyLm9yZyIsInZlciI6IjEuMCJ9.\\\"}\"", errorUri = Nothing}

From the error, it appears that Data.Aeson's decode function can't decode the JSON, but I am not sure why. Thinking that it might have to do with the JSON's extra fields, I made my own data AzureOAuth2Token type like the JSON with FromJSON instances, but the decode fails for that type too. Am I doing something wrong?

Clarify value of `oauthCallback` field in examples

In the examples for this library I see the following value oauthCallback for Fitbit IDP:

oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]

If I understood OAuth2 correctly then this should be URL that is called by Fitbit server in form:

http://localhost:9988/oauth2/callback?code=Foo&state=Bar

But how could it call my localhost? Does it mean that I can't test OAuth2 locally and I need some deployed globally accessible server for this, that implements /oauth2/callback?code=Foo&state=Bar endpoint?

Please release 0.3.6

I'm trying to use hoauth2 in a project with aeson 0.7, it'd be great if 0.3.6 were on Hackage.

Token must not be transmitted in both the parameters and headers (according to the standard)

I'm playing with the GMAIL API using hoauth2 and basically it doesn't work when the auth in included both in the URL and the header (as it is the case in your code). The implementation below works however (where only the header is used). Are you sure oauth2 allows to pass the auth in both in the header and url?

authGetBS' :: Manager                              -- ^ HTTP connection manager.
             -> AccessToken
             -> URI                               -- ^ URL
             -> IO (OAuth2Result BSL.ByteString)  -- ^ Response as ByteString
authGetBS' manager token url = liftM handleResponse go
                      where go = do
                                 -- was: req <- parseUrl $ BS.unpack $ url `appendAccessToken` token
                                 req <- parseUrl $ BS.unpack $ url
                                 authenticatedRequest manager token HT.GET req

Package structure thoughts

  • keep standard way to request access token and auth request in HttpClient.hs
  • move none-standard ways to x.y.z.Extra.hs
  • only take care request (JSON or FORM post) and response (in JSON). otherwise use a raw function at your own convenient. (response is bytestring)

https://www.googleapis.com/oauth2/v2/userinfo

This works

validateToken :: BS.ByteString -> IO BL.ByteString
validateToken accessToken = doSimplePostRequest ("https://www.googleapis.com/oauth2/v1/tokeninfo",(accessTokenToParam accessToken)) 

But this does not?

userinfo :: BS.ByteString -> IO BL.ByteString
userinfo accessToken = doSimplePostRequest ("https://www.googleapis.com/oauth2/v2/userinfo",(accessTokenToParam accessToken))

*** Exception: StatusCodeException (Status {statusCode = 404, statusMessage = "Not Found"}) [("Cache-Control","no-cache, no-store, max-age=0, must-revalidate"),("Pragma","no-cache"),("Expires","Fri, 01 Jan 1990 00:00:00 GMT"),("Date","Sun, 09 Dec 2012 03:32:03 GMT"),("Content-Type","text/html; charset=UTF-8"),("X-Content-Type-Options","nosniff"),("X-Frame-Options","SAMEORIGIN"),("X-XSS-Protection","1; mode=block"),("Server","GSE"),("Transfer-Encoding","chunked"),("X-Response-Body-Start","Not Found")]

Replace parse query code

replace

-- | Parses a @OAuth2Result BSL.ByteString@ that contains not JSON but a Query String
parseResponseString :: FromJSON a
              => OAuth2Result BSL.ByteString
              -> OAuth2Result a
parseResponseString (Left b) = Left b
parseResponseString (Right b) = case parseQuery $ BSL.toStrict b of
                              [] -> Left errorMessage
                              a -> case fromJSON $ queryToValue a of
                                    Error _   -> Left errorMessage
                                    Success x -> Right x
  where
    queryToValue = Object . HM.fromList . map paramToPair
    paramToPair (k, mv) = (T.decodeUtf8 k, maybe Null (String . T.decodeUtf8) mv)
    errorMessage = "hoauth2.HttpClient.parseResponseString/Could not decode URL: " `BSL.append` b

with https://hackage.haskell.org/package/http-types-0.9.1/docs/Network-HTTP-Types-URI.html#v:parseSimpleQuery

InvalidProfileResponse with Github

Hey,

Just wondering if you have any idea why i'm receiving this error when trying to authenticate with Github. I'm using yesod-auth-oauth2, which uses hoauth2. This worked several months ago. I've just recently updated all of my deps to the latest. I will try to figure it out myself but, just wondering if you've ever seen this.

InvalidProfileResponse "github" "hoauth2.HttpClient.parseResponseJSON/Could not decode JSON:

edit: Seems more like a yesod-auth-oauth2 issue.

Fetch access token and StackExchange

Hello.

I tried to authenticate with StackExchange.
Then, I have encountered problem similar to #32.

It responses url encoded access_token.
I'm getting error Could not decode JSONaccess_token=xxxxx&expires=86400.
And, I can't find endpoint that returns json.

Is there any fix about this issue ?
Should I change OAuth2.hs as @katyo did, and send PR ?

Could not decode JSON

I just tried an example of OAuth with Google and after login I get an error:

$ ./test-google                                               
https://accounts.google.com/o/oauth2/auth?client_id=726618178530.apps.googleusercontent.com&response_type=code&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile
visit the url and paste code here: 
< I paste code here >
AccessToken: AccessToken {accessToken = "__REMOVED__", refreshToken = Just "__REMOVED__"}
Left (Chunk "Could not decode JSON" (Chunk "{\n \"issued_to\": \"726618178530.apps.googleusercontent.com\",\n \"audience\": \"726618178530.apps.googleusercontent.com\",\n \"user_id\": \"__REMOVED__\",\n \"scope\": \"https://www.googleapis.com/auth/userinfo.profile\",\n \"expires_in\": 3600,\n \"access_type\": \"offline\"\n}\n" Empty))
Left (Chunk "Could not decode JSON" (Chunk "{\n \"issued_to\": \"726618178530.apps.googleusercontent.com\",\n \"audience\": \"726618178530.apps.googleusercontent.com\",\n \"user_id\": \"__REMOVED__\",\n \"scope\": \"https://www.googleapis.com/auth/userinfo.profile\",\n \"expires_in\": 3599,\n \"access_type\": \"offline\"\n}\n" Empty))
Left (Chunk "Could not decode JSON" (Chunk "{\n \"id\": \"__REMOVED__\",\n \"locale\": \"pl\"\n}\n" Empty))
Left (Chunk "Could not decode JSON" (Chunk "{\n \"id\": \"102710679971281134014\",\n \"locale\": \"pl\"\n}\n" Empty))

Authentication error with Google

My application and the test included in the repo now returns the following error when authenticating with Google: "OAuth 2 parameters can only have a single value: client_id"

I've just tried the test included in this repo and it seems to fail as well.

It is likely that hoauth2 isn't fully compliant with the standard. This issue pops up now because Google changed something recently -- see http://stackoverflow.com/questions/29694840/googles-openid-connect-says-oauth-2-parameters-can-only-have-a-single-value-c

Facebook: Error validating verification code.

I'm not sure it is a bug in your code or rather in my facebook app configuration. When I run it I get an error:

➜  hoauth2 git:(master) ✗ ./example/Facebook/test 
"https://www.facebook.com/dialog/oauth?client_id=317076475103268&response_type=code&redirect_uri=http%3A%2F%2Flocalhost&scope=user_about_me%2Cemail"
visit the url and paste code here: 
__REMOVED__
test: StatusCodeException (Status {statusCode = 400, statusMessage = "Bad Request"}) [("Access-Control-Allow-Origin","*"),("Cache-Control","no-store"),("Content-Type","application/json"),("Expires","Sat, 01 Jan 2000 00:00:00 GMT"),("Pragma","no-cache"),("WWW-Authenticate","OAuth \"Facebook Platform\" \"invalid_code\" \"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request\""),("X-FB-Rev","924754"),("X-FB-Debug","__REMOVED__"),("Date","Tue, 03 Sep 2013 08:37:37 GMT"),("Connection","keep-alive"),("Content-Length","190"),("X-Response-Body-Start","{\"error\":{\"message\":\"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request\",\"type\":\"OAuthException\",\"code\":100}}")] (CJ {expose = []})

I have listed http://localhost in "Valid OAuth redirect URIs" in facebook app configuration

`fetchRefreshToken` fails, expecting `Text` but receiving `Object`

I tried to set up a working Google integration today and ran into this error when trying to refresh an access token (I could not get the examples to build and refresh properly, either):

Left "hoauth2.HttpClient.parseResponseString/Could not decode URL: {\n  \"access_token\" : \"lt_...EFpxs_m\",\n  \"expires_in\" : 3600,\n  \"id_token\" : \"eyJhbGc...6VO_CRWw\",\n  \"token_type\" : \"Bearer\"\n}"

I was puzzled, as fetching an access token works perfectly well. I found that this function relies on doFlexiblePostRequest, which tries first to parse the JSON and then to parse the URL. So this error is misleading. By forcing it to try the JSON, I saw this:

Left "hoauth2.HttpClient.parseResponseJSON/Could not decode JSON: {\n \"access_token\": \"y...cyuCn9YY6SpPd0P4GHlWpcBgg9_o8uVX2RiBHYY0As2Y8wmmHUmO\",\n \"token_type\": \"Bearer\",\n \"expires_in\": 3600\n}\n, with error: 
Error in $: expected Text, encountered Object"

This was confusing, until I realized the instance of FromJSON for AccessToken, the return type for this function, is just this:

newtype AccessToken = AccessToken { atoken :: Text } deriving (Show, FromJSON, ToJSON)

But what Google sends over is this:

{
\n \"access_token\": \"y...G\",
\n \"token_type\": \"Bearer\",
\n \"expires_in\": 3600\n}
}

To remedy the problem, I made a new data type that I could derive instances from just as is done with the overall OAuth2Token. The code written below works successfully to refresh tokens.

data OAuthRefreshToken = OAuthRefreshToken {
      accessToken :: AccessToken
    , tokenType   :: Maybe Text
    , expiresIn   :: Maybe Int
    } deriving (Show, Generic)

instance FromJSON OAuthRefreshToken where
    parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '_' }
instance ToJSON OAuthRefreshToken where
    toEncoding = genericToEncoding defaultOptions { fieldLabelModifier = camelTo2 '_' }

fetchRefreshToken ::
     Manager
  -> OAuth2
  -> RefreshToken
  -> IO (OAuth2Result OAuthRefreshToken)
fetchRefreshToken manager oa token = doJSONPostRequest manager oa uri body
    where (uri, body) = refreshAccessTokenUrl oa token

I don't know what you'd prefer to do as the answer to this problem so I haven't submitted a PR. Instead, I'm sharing my solution here.

Cheers!
Thomas

Improve the readme

  1. add small steps regarding build and use the demo server
  2. call out how to config Keys.hs in order to make the demo server work

3rd round demo server refactor

make open data type (IDP now is so called close data type, cause whenever needs a new IDP, the data structure needs to be update)

Update Dependencies

Hi,

can you update the dependencies for this cabal package?

I tested it with:

http-conduit-1.6.0
conduit-0.5.2.3
http-types-0.7.2

and found no problems.

Security issue on exceptions

Certain responses (like 401) from the OAuth provider can cause exceptions to be thrown when calling authGetJSON. This is problematic because Yesod displays exceptions to the end user automatically, which can contain the URL including GET variables with secret access tokens.

As a temporary fix, I've wrapped authGetJSON with catchAny from Control.Exception.Enclosed.

authGetJSON' manager token url = catchAny (authGetJSON manager token url) handler
    where
        handler e = return $ Left $ BSL8.pack $ show e

Integration with Twitter

I'm glad to use your library in my project but I need also integration with Twitter. Is there any chance for the Twitter implementation any time soon?

Service Account

Damian Soriano (Gmail) to me Aug 8
Hi!

I am creating a Haskell application that connects go bigquery. I wanted to use your OAuth2 lib to do that: https://github.com/freizl/hoauth2

I search a little bit in the doc and example and I didn't found anything about service account authentication (https://developers.google.com/identity/protocols/OAuth2ServiceAccount). I was wondering if that feature is already implemented in the lib or not, since I found no example about that.

Many thanks

Regards

Facebook OAuth 'missing client_id' in versions > 0.5.5

After upgrading hoauth2 to anything above 0.5.5 I receive the following error from Facebook when making a POST request to retrieve an access token:

 {\"error\":{\"message\":\"Missing client_id    parameter.\",\"type\":\"OAuthException\",\"code\":101,\"fbtrace_id\":\"AKOkEeCq8LL\"}}

The code that invokes this didn't change since the upgrade, and is as follows:

      get "/oauth/facebook" $ do
        r <- request
        code <- param "code"
        mgr <- liftIO $ newManager tlsManagerSettings
        let (url, body) = accessTokenUrl oauthConf code
        resp <- liftIO $ doJSONPostRequest mgr oauthConf url (body ++ [("state", "test")])
        case (resp :: OAuth2Result AccessToken) of
          Right token -> do
            user <- liftIO $ userinfo' mgr token

Was the client_id removed from being set in the query parameters in the doJSONPostRequest? I took a look at the source code and it doesn't look like that method or the helper methods it invokes changes.

fetch*Token and Facebook

I was confused, but Facebook's response body contains URL-encoded string, not JSON-encoded.

I got an error:

Could not decode JSONaccess_token=…&expires=…

Library isn't working with Google Gmail API

I'm trying to use authPostBS to send emails through Gmail API. I'm running into two issues:

  1. Functions authPostBS adds the token to the body and the headers, which I believe deviates from the OAuth 2 specs.
  2. When using authPost* family of functions, there is no way to set the content type header as far as I see.

To make my code work I had to implement something like below (see authPostBS99). I also had to change the updateRequestHeaders function to add the missing application/json. This is not ideal as it breaks backward compatibility.

Is there something I'm missing here? Has this code been tested with Google API?

-- | Conduct POST request.
authPostBS99 :: FromJSON err => Manager                -- ^ HTTP connection manager.
             -> AccessToken
             -> URI
             -> BSL.ByteString
             -> IO (OAuth2Result err BSL.ByteString) -- ^ Response as ByteString
authPostBS99 manager token url body = do
  req <- uriToRequest url
  authRequest req upReq manager
  where upBody req = req { requestBody = RequestBodyLBS body }
        upHeaders = updateRequestHeaders (Just token) . setMethod HT.POST
        upReq = upHeaders . upBody

Warning: Unable to find a known candidate for the Cabal entry Keys

When I'm adding hoauth2 library to the dependencies of my project, I see the following warning when I build project with stack-1.7.1:

Warning: Unable to find a known candidate for the Cabal entry Keys, but did find:
         * Keys.hs.sample If you are using a custom preprocessor for this module with its own file extension, consider adding the file(s) to your .cabal under extra-source-files.

Version of hoauth2 library: 1.7.2

Recheck the origin PR to add static type for error

  • #61
  • Why OAuth2Error error instead of OAuth2Error ?
    • looks like was trying to use same data type for both Auth code error and Token request error.
    • I still wonder if following would work better?
data TokenError = A | B | C | UnknownTokenErrorCode Text
instance FromJSON TokenError where
  parse to token error otherwise 'UnknownTokenErrorCode Text'

data OAuth2Error e =
  { error :: e 
  , description :: Maybe Text
  , error_uri :: Maybe URI
  }

but the problem is e has to be able to parsed from JSON. Given e can be any type, doing error :: Either Text e feels safer. Unless

data OAuth2ErrorCode = AuthCode.Error | TokenCode.Error

AuthCode.Error = A | B | C | UnknownCode Text
TokenCode.Error = A | B | D | E | UnknownCode Text

data OAuth2Error (e :: OAuth2ErrorCode) =
  { error :: e 
  , description :: Maybe Text
  , error_uri :: Maybe URI
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.