diff --git a/example/IDP.hs b/example/IDP.hs
--- a/example/IDP.hs
+++ b/example/IDP.hs
@@ -4,6 +4,7 @@
 import           Data.Text.Lazy      (Text)
 
 import qualified Data.HashMap.Strict as Map
+import qualified IDP.AzureAD         as IAzureAD
 import qualified IDP.Douban          as IDouban
 import qualified IDP.Dropbox         as IDropbox
 import qualified IDP.Facebook        as IFacebook
@@ -19,7 +20,8 @@
 -- TODO: make this generic to discover any IDPs from idp directory.
 --
 idps :: [IDPApp]
-idps = [ IDPApp IDouban.Douban
+idps = [ IDPApp IAzureAD.AzureAD
+       , IDPApp IDouban.Douban
        , IDPApp IDropbox.Dropbox
        , IDPApp IFacebook.Facebook
        , IDPApp IFitbit.Fitbit
diff --git a/example/IDP/AzureAD.hs b/example/IDP/AzureAD.hs
new file mode 100644
--- /dev/null
+++ b/example/IDP/AzureAD.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes       #-}
+
+module IDP.AzureAD where
+import Data.Aeson
+import Data.Bifunctor
+import Data.Hashable
+import Data.Text.Lazy (Text)
+import GHC.Generics
+import Keys
+import Network.OAuth.OAuth2
+import Types
+import URI.ByteString
+import URI.ByteString.QQ
+import Utils
+
+data AzureAD = AzureAD deriving (Show, Generic)
+
+instance Hashable AzureAD
+
+instance IDP AzureAD
+
+instance HasLabel AzureAD
+
+instance HasTokenReq AzureAD where
+  tokenReq _ mgr = fetchAccessToken mgr azureADKey
+
+instance HasUserReq AzureAD where
+  userReq _ mgr at = do
+    re <- authGetJSON mgr at userInfoUri
+    return (second toLoginUser re)
+
+instance HasAuthUri AzureAD where
+  authUri _ = createCodeUri azureADKey [ ("state", "AzureAD.test-state-123")
+                                       , ("scope", "openid,profile")
+                                       , ("resource", "https://graph.microsoft.com")
+                                       ]
+
+newtype AzureADUser = AzureADUser { mail :: Text } deriving (Show, Generic)
+
+instance FromJSON AzureADUser where
+    parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '_' }
+
+userInfoUri :: URI
+userInfoUri = [uri|https://graph.microsoft.com/v1.0/me|]
+
+toLoginUser :: AzureADUser -> LoginUser
+toLoginUser ouser = LoginUser { loginUserName = mail ouser }
diff --git a/example/Keys.hs b/example/Keys.hs
--- a/example/Keys.hs
+++ b/example/Keys.hs
@@ -84,3 +84,11 @@
                  , oauthOAuthorizeEndpoint = [uri|https://dev-148986.oktapreview.com/oauth2/v1/authorize|]
                  , oauthAccessTokenEndpoint = [uri|https://dev-148986.oktapreview.com/oauth2/v1/token|]
                  }
+
+azureADKey :: OAuth2
+azureADKey = OAuth2 { oauthClientId = "xxx"
+                    , oauthClientSecret = "xxx"
+                    , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
+                    , oauthOAuthorizeEndpoint = [uri|https://login.windows.net/common/oauth2/authorize|]
+                    , oauthAccessTokenEndpoint = [uri|https://login.windows.net/common/oauth2/token|]
+                    }
diff --git a/example/Keys.hs.sample b/example/Keys.hs.sample
--- a/example/Keys.hs.sample
+++ b/example/Keys.hs.sample
@@ -84,3 +84,11 @@
                  , oauthOAuthorizeEndpoint = [uri|https://dev-148986.oktapreview.com/oauth2/v1/authorize|]
                  , oauthAccessTokenEndpoint = [uri|https://dev-148986.oktapreview.com/oauth2/v1/token|]
                  }
+
+azureADKey :: OAuth2
+azureADKey = OAuth2 { oauthClientId = "xxx"
+                    , oauthClientSecret = "xxx"
+                    , oauthCallback = Just [uri|http://localhost:9988/oauth2/callback|]
+                    , oauthOAuthorizeEndpoint = [uri|https://login.windows.net/common/oauth2/authorize|]
+                    , oauthAccessTokenEndpoint = [uri|https://login.windows.net/common/oauth2/token|]
+                    }
diff --git a/example/README.md b/example/README.md
--- a/example/README.md
+++ b/example/README.md
@@ -1,6 +1,7 @@
 
 * IDPs
-  - douban: http://developers.douban.com/wiki/?title=oauth2
+  - AzureAD: <https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code>
+  - douban: <http://developers.douban.com/wiki/?title=oauth2>
   - Google: <https://developers.google.com/accounts/docs/OAuth2WebServer>
   - Github: <http://developer.github.com/v3/oauth/>
   - Facebook: <http://developers.facebook.com/docs/facebook-login/>
diff --git a/hoauth2.cabal b/hoauth2.cabal
--- a/hoauth2.cabal
+++ b/hoauth2.cabal
@@ -1,11 +1,13 @@
 Name:                hoauth2
 -- http://wiki.haskell.org/Package_versioning_policy
-Version:             1.8.1
+Version:             1.8.2
 
 Synopsis:            Haskell OAuth2 authentication client
 
 Description: Haskell OAuth2 authentication client. Tested with the following services:
              .
+             * AzureAD: <https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code>
+             .
              * Google: <https://developers.google.com/accounts/docs/OAuth2WebServer>
              .
              * Github: <http://developer.github.com/v3/oauth/>
@@ -35,6 +37,7 @@
 
 Extra-source-files: README.md
                     example/Keys.hs.sample
+                    example/IDP/AzureAD.hs
                     example/IDP/Google.hs
                     example/IDP/Weibo.hs
                     example/IDP/Github.hs
@@ -99,6 +102,7 @@
   main-is:             main.hs
   other-modules:       IDP,
                        App
+                       IDP.AzureAD
                        IDP.Douban
                        IDP.Dropbox
                        IDP.Facebook
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
@@ -18,6 +18,7 @@
 import qualified Data.ByteString      as BS
 import qualified Data.ByteString.Lazy as BSL
 import           Data.Maybe
+import           Data.Semigroup       ((<>))
 import           Data.Text            (Text, pack, unpack)
 import           Data.Text.Encoding
 import           GHC.Generics
