diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,8 +1,17 @@
 [![Build Status](https://secure.travis-ci.org/freizl/hoauth2.svg?branch=master)](http://travis-ci.org/freizl/hoauth2)
 [![Hackage](https://img.shields.io/hackage/v/hoauth2.svg)](https://hackage.haskell.org/package/hoauth2)
+
 # Introduction
 
-A lightweight oauth2 haskell binding. See examples in `example/` folder.
+A lightweight oauth2 haskell binding.
+
+# Build example app
+
+- `make create-keys`
+- check the `example/Keys.hs` to make sure it's config correctly for the IdP you're going to test. (client id, client secret, oauth Urls etc)
+- `make build`
+- `make demo`
+- open <http://localhost:9988>
 
 # Contribute
 
diff --git a/example/IDP/Douban.hs b/example/IDP/Douban.hs
--- a/example/IDP/Douban.hs
+++ b/example/IDP/Douban.hs
@@ -4,7 +4,6 @@
 
 module IDP.Douban where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.Hashable
 import           Data.Text.Lazy       (Text)
diff --git a/example/IDP/Dropbox.hs b/example/IDP/Dropbox.hs
--- a/example/IDP/Dropbox.hs
+++ b/example/IDP/Dropbox.hs
@@ -4,7 +4,6 @@
 
 module IDP.Dropbox where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.Hashable
 import           Data.Text.Lazy       (Text)
diff --git a/example/IDP/Facebook.hs b/example/IDP/Facebook.hs
--- a/example/IDP/Facebook.hs
+++ b/example/IDP/Facebook.hs
@@ -4,7 +4,6 @@
 
 module IDP.Facebook where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.Hashable
 import           Data.Text.Lazy       (Text)
diff --git a/example/IDP/Github.hs b/example/IDP/Github.hs
--- a/example/IDP/Github.hs
+++ b/example/IDP/Github.hs
@@ -4,7 +4,6 @@
 
 module IDP.Github where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.Hashable
 import           Data.Text.Lazy       (Text)
diff --git a/example/IDP/Google.hs b/example/IDP/Google.hs
--- a/example/IDP/Google.hs
+++ b/example/IDP/Google.hs
@@ -4,7 +4,6 @@
 
 module IDP.Google where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.Hashable
 import           Data.Text.Lazy       (Text)
diff --git a/example/IDP/Okta.hs b/example/IDP/Okta.hs
--- a/example/IDP/Okta.hs
+++ b/example/IDP/Okta.hs
@@ -4,7 +4,6 @@
 
 module IDP.Okta where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.Hashable
 import           Data.Text.Lazy       (Text)
diff --git a/example/IDP/StackExchange.hs b/example/IDP/StackExchange.hs
--- a/example/IDP/StackExchange.hs
+++ b/example/IDP/StackExchange.hs
@@ -8,7 +8,6 @@
 -}
 module IDP.StackExchange where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.ByteString      (ByteString)
 import           Data.Hashable
diff --git a/example/IDP/Weibo.hs b/example/IDP/Weibo.hs
--- a/example/IDP/Weibo.hs
+++ b/example/IDP/Weibo.hs
@@ -4,7 +4,6 @@
 
 module IDP.Weibo where
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Bifunctor
 import           Data.Hashable
 import           Data.Text.Lazy       (Text)
diff --git a/example/Keys.hs b/example/Keys.hs
--- a/example/Keys.hs
+++ b/example/Keys.hs
@@ -8,101 +8,79 @@
 import           URI.ByteString.QQ
 
 weiboKey :: OAuth2
-weiboKey = OAuth2 { oauthClientId = "1962132691"
-                  , oauthClientSecret = "a2ad30383bdff9bcb12be6a3d30deeb1"
-                  , oauthCallback = Just [uri|http://127.0.0.1:9988/oauth2/callback|]
-                  , oauthOAuthorizeEndpoint = [uri|https://api.weibo.com/oauth2/authorize|]
-                  , oauthAccessTokenEndpoint = [uri|https://api.weibo.com/oauth2/access_token|]
-                  }
+weiboKey = OAuth2 { oauthClientId = "xxxxxxxxxxxxxxx"
+                   , oauthClientSecret = "xxxxxxxxxxxxxxxxxxxxxx"
+                   , oauthCallback = Just [uri|http://127.0.0.1:9988/oauthCallback|]
+                   , oauthOAuthorizeEndpoint = [uri|https://api.weibo.com/oauth2/authorize|]
+                   , oauthAccessTokenEndpoint = [uri|https://api.weibo.com/oauth2/access_token|]
+                   }
 
 -- | http://developer.github.com/v3/oauth/
 githubKey :: OAuth2
-githubKey = OAuth2 { oauthClientId = "bf86d338485a96a93c88"
-                   , oauthClientSecret = "a1c00dada665dc00aa6fafe0495c7c885f82d1ce"
-                   , oauthCallback = Just [uri|http://127.0.0.1:9988/oauth2/callback|]
-                   , oauthOAuthorizeEndpoint = [uri|https://github.com/login/oauth/authorize|]
-                   , oauthAccessTokenEndpoint = [uri|https://github.com/login/oauth/access_token|]
-                   }
+githubKey = OAuth2 { oauthClientId = "xxxxxxxxxxxxxxx"
+                    , oauthClientSecret = "xxxxxxxxxxxxxxxxxxxxxx"
+                    , oauthCallback = Just [uri|http://127.0.0.1:9988/githubCallback|]
+                    , oauthOAuthorizeEndpoint = [uri|https://github.com/login/oauth/authorize|]
+                    , oauthAccessTokenEndpoint = [uri|https://github.com/login/oauth/access_token|]
+                    }
 
 -- | oauthCallback = Just "https://developers.google.com/oauthplayground"
 googleKey :: OAuth2
-googleKey = OAuth2 { oauthClientId = "886894027376.apps.googleusercontent.com"
-                   , oauthClientSecret = "27w98gwGB1h8N5a6JQ2bT_nm"
-                   , oauthCallback = Just [uri|http://127.0.0.1:9988/oauth2/callback|]
+googleKey = OAuth2 { oauthClientId = "xxxxxxxxxxxxxxx.apps.googleusercontent.com"
+                   , oauthClientSecret = "xxxxxxxxxxxxxxxxxxxxxx"
+                   , oauthCallback = Just [uri|http://127.0.0.1:9988/googleCallback|]
                    , oauthOAuthorizeEndpoint = [uri|https://accounts.google.com/o/oauth2/auth|]
                    , oauthAccessTokenEndpoint = [uri|https://www.googleapis.com/oauth2/v3/token|]
                    }
 
-{-
-googleServiceAccount :: GoogleServiceAccount
-googleServiceAccount = GoogleServiceAccount
-  { saPrivateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDfu/z7ASRGrQus\ngWABWNX/EKgE8NlEUoHUeDWCTpXVj6PmiEDGyRaBNqR+6fQmwBMD/ItpISTGT31/\nfdqhKAdJOaYGNvWNYxx1uWYm0HP1YU7OkfFt8YgROu8gGz7+mdseXs/3bMhjlbk9\nPKmBiU46VRFWn7QaAp9YiVGghZp/LcawC+urmWdYnpkl+P4C4u+YtszmCMql842M\nT4nK8jlraxvUT/XM+97UXKwiGL8sPiPKGEthAFiXHNRVgnDibnJ2Etw7zPbZ6FB+\nvHL1SkuSnE7C358RTkuz56Tvf6ETgOGDIJ9HpZlgT6hrsWcAOh8UZ34Q5QzinhtP\n5BdgQxnjAgMBAAECggEBAJqfxFYA0v5ZZ+D/xMcJi1PtQgGwJqf2Ua3yqiB1iU4A\nKKkRb5syrG/+wK7Jp6gEROATcJHmixDXLQeohimsjWSJB/nxj8D4R1oBGN0oYYur\nhZhz+qQeMgieb1cEHYQ99tbFdfss3k0c09nDi+5vY3YjBomUdBcpytCYjqZez4im\nYoZjA6ijb5BduCQO2YOJpjiHbSrTV05Zr/xfHgafkbRx04jHA7OdJM6x5giRcMBn\n5BYNGPUkM6mGpeTeCZjTsOqvXcckuyR8P4wzoG3J8grnXgGR17d829t0bi5X/Jym\nwj5707lvIqu+WcfUfXDDYkZNhe5S9PWpT1uqaOGWElECgYEA738wclTGRNboYLsx\noT6HCOEKNFiY/4DMV65nugSnHBIl4amLwm4+0v669F8F28U2xhihp+RfPC4Fjd62\nfJ9hlYg6NiEqReJfXhs5OcvMBjmBFUR046/kOGyEj6D2yn3LTXoiWI8tHaS0Ucmu\nwF4Lp0/Rk/ofQrFB7q1a0OBeTakCgYEA7ya+IMo0t4lRYl+x8A7ouuJwnK1VjkkC\nkloCAEsnVznb2BsHJCsF0fPPU3f+kqhYqD0qQCfbwhYGragt603a/BqXnnQyE9T/\nnLqSGgctY/Xr06HbOr+aZ4QLKsTfD6IkTC82WAJD3J8hptLaqqDMORluI6xchKEL\nNUV8uvX7qqsCgYEAtKo/w5+LyZZMydusfrSKbPpGFmLXV7azb1lTShIEdbqC9Q5P\nLaa4obYjFgEwjC7jOOCP4fT2mpElA3aENtKMbJ7NOtQd7YXs5zKmIqFIEVIDvCVd\n//xJrv69qROF2A649IMzsZagNAJxPFlmCBtpsxcVRAmk10ycLg57uaHnwbECgYEA\nrtqn1rehVbQ74e5P3lI4TTP03ElLra2qCLFwlyBb0kXGfLo+PW6LYdeedcvdQQN/\nVvrpomDCJ6UNGvlFIa8Z9ovG4Z7ZYnCwt7odypQG1vhehazo6ope7WK4+3tYEEkf\nuugmFrEJRwy+gQfXwzuwNetnAQQr3PkWhcuZh+UELeMCgYAPoQK1LETBLFsUBWhh\nHc5VrnQBykn9GMRPXKR4pq5MK8p8o2QwfL5hNlZNeTKPWdP0QtMuIH9gxRuqvbrF\nXEO8RmZmoNtznh/Ax7+S62g72iLzF1/C8j3g8hWJUeGlU8LAJsZVTSma3t/vEQZM\nQqydJfwXJMTkh4nslALJZ9S4bw==\n-----END PRIVATE KEY-----\n"
-  , saEmail = "testoauth2sa@api-project-886894027376.iam.gserviceaccount.com"
-  , saScope = [ "https://www.googleapis.com/auth/prediction"
-              , "https://www.googleapis.com/auth/drive"
-              ]
-  , saAuthEndpoint = "https://www.googleapis.com/oauth2/v4/token"
-  , saExpireTime = Nothing
-  , saDelegateEmail = Nothing
-  }
--}
-
 facebookKey :: OAuth2
-facebookKey = OAuth2 { oauthClientId = "414630782030965"
-                     , oauthClientSecret = "0e648eae100da4d03f16594f231fc1d0"
-                     , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
+facebookKey = OAuth2 { oauthClientId = "xxxxxxxxxxxxxxx"
+                     , oauthClientSecret = "xxxxxxxxxxxxxxxxxxxxxx"
+                     , oauthCallback = Just [uri|http://t.haskellcn.org/cb|]
                      , oauthOAuthorizeEndpoint = [uri|https://www.facebook.com/dialog/oauth|]
-                     , oauthAccessTokenEndpoint = [uri|https://graph.facebook.com/v2.12/oauth/access_token|]
+                     , oauthAccessTokenEndpoint = [uri|https://graph.facebook.com/v2.3/oauth/access_token|]
                      }
 
 doubanKey :: OAuth2
-doubanKey = OAuth2 { oauthClientId = "02a914cf299ca31607fb3e6d7cd5e942"
-                   , oauthClientSecret = "3c0fdef13b0dd271"
-                   , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
+doubanKey = OAuth2 { oauthClientId = "xxxxxxxxxxxxxxx"
+                   , oauthClientSecret = "xxxxxxxxxxxxxxxxxxxxxx"
+                   , oauthCallback = Just [uri|http://localhost:9999/oauthCallback|]
                    , oauthOAuthorizeEndpoint = [uri|https://www.douban.com/service/auth2/auth|]
                    , oauthAccessTokenEndpoint = [uri|https://www.douban.com/service/auth2/token|]
                    }
 
 fitbitKey :: OAuth2
-fitbitKey = OAuth2 { oauthClientId = "229LN9"
-                   , oauthClientSecret = "2f4aa9a275c2d4bb9eb616efbd2c1311"
+fitbitKey = OAuth2 { oauthClientId = "xxxxxx"
+                   , oauthClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                    , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
                    , oauthOAuthorizeEndpoint = [uri|https://www.fitbit.com/oauth2/authorize|]
                    , oauthAccessTokenEndpoint = [uri|https://api.fitbit.com/oauth2/token|]
                    }
 
+-- fix key from your application edit page
+-- https://stackapps.com/apps/oauth
 stackexchangeAppKey :: ByteString
-stackexchangeAppKey = "LZvAveRFYw8lgNluEU2pDQ(("
+stackexchangeAppKey = "xxxxxx"
 
 stackexchangeKey :: OAuth2
-stackexchangeKey = OAuth2 { oauthClientId = "7185"
-                          , oauthClientSecret = "K5hK)ET*dbFGFmNFVtqIyA(("
-                          , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
+stackexchangeKey = OAuth2 { oauthClientId = "xx"
+                          , oauthClientSecret = "xxxxxxxxxxxxxxx"
+                          , oauthCallback = Just [uri|http://c.haskellcn.org/cb|]
                           , oauthOAuthorizeEndpoint = [uri|https://stackexchange.com/oauth|]
-                          , oauthAccessTokenEndpoint = [uri|https://stackexchange.com/oauth/access_token/json|]
+                          , oauthAccessTokenEndpoint = [uri|https://stackexchange.com/oauth/access_token|]
                           }
-
 dropboxKey :: OAuth2
-dropboxKey = OAuth2 { oauthClientId = "zbyxxox19gz6dgg"
-                    , oauthClientSecret = "ihhui0ysp85oi8s"
+dropboxKey = OAuth2 { oauthClientId = "xxx"
+                    , oauthClientSecret = "xxx"
                     , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
                     , oauthOAuthorizeEndpoint = [uri|https://www.dropbox.com/1/oauth2/authorize|]
                     , oauthAccessTokenEndpoint = [uri|https://api.dropboxapi.com/oauth2/token|]
                     }
 
 oktaKey :: OAuth2
-oktaKey = OAuth2 { oauthClientId = "0oad3popatwUIhWV40h7"
-                 , oauthClientSecret = "YFqXRjtsy7IYRbueiG2tcgHzhaawLccxqq5ruPfN"
+oktaKey = OAuth2 { oauthClientId = "xxx"
+                 , oauthClientSecret = "xxx"
                  , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
                  , oauthOAuthorizeEndpoint = [uri|https://dev-148986.oktapreview.com/oauth2/v1/authorize|]
                  , oauthAccessTokenEndpoint = [uri|https://dev-148986.oktapreview.com/oauth2/v1/token|]
                  }
-
-linkedinKey :: OAuth2
-linkedinKey = OAuth2 { oauthClientId = "86r7dx3b0piy56"
-                     , oauthClientSecret = "lBb5kA5lpggHT0Ne"
-                     , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
-                     , oauthOAuthorizeEndpoint = [uri|https://www.linkedin.com/oauth/v2/authorization|]
-                     , oauthAccessTokenEndpoint = [uri|https://www.linkedin.com/oauth/v2/accessToken|]
-                     }
-
diff --git a/example/README.md b/example/README.md
--- a/example/README.md
+++ b/example/README.md
@@ -1,3 +1,4 @@
+
 * IDPs
   - douban: http://developers.douban.com/wiki/?title=oauth2
   - Google: <https://developers.google.com/accounts/docs/OAuth2WebServer>
@@ -9,5 +10,5 @@
   - DropBox: <https://www.dropbox.com/developers/reference/oauth-guide>
   - Weibo: <http://open.weibo.com/wiki/Oauth2>
 
-** Linkedin
+* WIP: Linkedin
   - <https://developer.linkedin.com>
diff --git a/example/Types.hs b/example/Types.hs
--- a/example/Types.hs
+++ b/example/Types.hs
@@ -9,7 +9,6 @@
 
 import           Control.Concurrent.MVar
 import           Data.Aeson
-import           Data.Aeson.Types
 import           Data.Hashable
 import qualified Data.HashMap.Strict               as Map
 import           Data.Maybe
@@ -45,6 +44,9 @@
 class (IDP a) => HasUserReq a where
   userReq :: FromJSON b => a -> Manager -> AccessToken -> IO (OAuth2Result b LoginUser)
 
+-- Heterogenous collections
+-- https://wiki.haskell.org/Heterogenous_collections
+--
 data IDPApp = forall a. (IDP a, HasTokenReq a, HasUserReq a, HasLabel a, HasAuthUri a) => IDPApp a
 
 -- dummy oauth2 request error
diff --git a/hoauth2.cabal b/hoauth2.cabal
--- a/hoauth2.cabal
+++ b/hoauth2.cabal
@@ -1,6 +1,6 @@
 Name:                hoauth2
 -- http://wiki.haskell.org/Package_versioning_policy
-Version:             1.7.2
+Version:             1.8.0
 
 Synopsis:            Haskell OAuth2 authentication client
 
@@ -77,12 +77,12 @@
                  bytestring           >= 0.9   && < 0.11,
                  http-conduit         >= 2.1   && < 2.4,
                  http-types           >= 0.11   && < 0.13,
-                 aeson                >= 0.11  && < 1.4,
+                 aeson                >= 1.0.0.0 && < 1.4,
                  unordered-containers >= 0.2.5,
                  uri-bytestring       >= 0.2.3.1 && < 0.4,
                  uri-bytestring-aeson >= 0.1   && < 0.2,
                  microlens            >= 0.4.0 && < 0.5,
-                 exceptions           >= 0.8.3 && < 0.10
+                 exceptions           >= 0.8.3 && < 0.11
 
   if impl(ghc >= 6.12.0)
       ghc-options: -Wall -fwarn-tabs -funbox-strict-fields
@@ -125,15 +125,15 @@
                        wai               >= 3.2    && < 3.3,
                        warp              >= 3.2    && < 3.3,
                        containers        >= 0.4    && < 0.6,
-                       aeson             >= 0.11   && < 1.4,
+                       aeson             >= 1.0.0.0 && < 1.4,
                        microlens            >= 0.4.0 && < 0.5,
-                       unordered-containers >= 0.2.8 && < 0.2.9,
-                       wai-extra >= 3.0.21.0 && < 3.0.22.0,
-                       wai-middleware-static == 0.8.1,
-                       mustache >= 2.2.3 && < 2.3.0,
+                       unordered-containers >= 0.2.8 && < 0.2.10,
+                       wai-extra >= 3.0.21.0 && < 3.0.25.0,
+                       wai-middleware-static >= 0.8.1 && < 0.8.3,
+                       mustache >= 2.2.3 && < 2.4.0,
                        mtl >= 2.2.1 && < 2.3,
-                       scotty == 0.10.0,
-                       binary >= 0.8.3.0 && < 0.8.5,
+                       scotty >= 0.10.0 && < 0.12,
+                       binary >= 0.8.3.0 && < 0.8.6,
                        parsec >= 3.1.11 && < 3.2.0 ,
                        hashable >= 1.2.6 && < 1.3.0,
                        hoauth2
diff --git a/src/Network/OAuth/OAuth2/AuthorizationRequest.hs b/src/Network/OAuth/OAuth2/AuthorizationRequest.hs
--- a/src/Network/OAuth/OAuth2/AuthorizationRequest.hs
+++ b/src/Network/OAuth/OAuth2/AuthorizationRequest.hs
@@ -3,7 +3,6 @@
 module Network.OAuth.OAuth2.AuthorizationRequest where
 
 import           Data.Aeson
-import           Data.Aeson.Types
 import           GHC.Generics
 
 instance FromJSON Errors where
diff --git a/src/Network/OAuth/OAuth2/Internal.hs b/src/Network/OAuth/OAuth2/Internal.hs
--- a/src/Network/OAuth/OAuth2/Internal.hs
+++ b/src/Network/OAuth/OAuth2/Internal.hs
@@ -14,11 +14,9 @@
 import           Control.Arrow        (second)
 import           Control.Monad.Catch
 import           Data.Aeson
-import           Data.Aeson.Types
 import qualified Data.ByteString      as BS
 import qualified Data.ByteString.Lazy as BSL
 import           Data.Maybe
-import           Data.Monoid
 import           Data.Text            (Text, pack)
 import           Data.Text.Encoding
 import           GHC.Generics
@@ -64,6 +62,7 @@
 instance FromJSON OAuth2Token where
     parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '_' }
 instance ToJSON OAuth2Token where
+    toJSON = genericToJSON defaultOptions { fieldLabelModifier = camelTo2 '_' }
     toEncoding = genericToEncoding defaultOptions { fieldLabelModifier = camelTo2 '_' }
 
 data OAuth2Error a =
@@ -83,6 +82,7 @@
   parseJSON _ = fail "Expected an object"
 
 instance ToJSON err => ToJSON (OAuth2Error err) where
+  toJSON = genericToJSON defaultOptions { constructorTagModifier = camelTo2 '_', allNullaryToStringTag = True }
   toEncoding = genericToEncoding defaultOptions { constructorTagModifier = camelTo2 '_', allNullaryToStringTag = True }
 
 parseOAuth2Error :: FromJSON err => BSL.ByteString -> OAuth2Error err
@@ -135,7 +135,7 @@
 accessTokenUrl' oa code gt = (uri, body)
   where uri  = oauthAccessTokenEndpoint oa
         body = catMaybes [ Just ("code", encodeUtf8 $ extoken code)
-                         , (("redirect_uri",) . serializeURIRef') <$> oauthCallback oa
+                         , ("redirect_uri",) . serializeURIRef' <$> oauthCallback oa
                          , fmap (("grant_type",) . encodeUtf8) gt
                          ]
 
diff --git a/src/Network/OAuth/OAuth2/TokenRequest.hs b/src/Network/OAuth/OAuth2/TokenRequest.hs
--- a/src/Network/OAuth/OAuth2/TokenRequest.hs
+++ b/src/Network/OAuth/OAuth2/TokenRequest.hs
@@ -3,7 +3,6 @@
 module Network.OAuth.OAuth2.TokenRequest where
 
 import           Data.Aeson
-import           Data.Aeson.Types
 import           GHC.Generics
 
 instance FromJSON Errors where
