diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,13 @@
 
+50200.12.0
+==========
+
+Package changes:
+ * Changed Aeson dependency to 2.0 to support GHC 9.
+
+New features:
+ * 2FA support (thanks @msm-code)
+
 50200.11.0
 ==========
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
 [![Hackage](https://img.shields.io/hackage/v/mattermost-api.svg)](https://hackage.haskell.org/package/mattermost-api) [![Build
 Status](https://travis-ci.org/matterhorn-chat/mattermost-api.svg?branch=master)](https://travis-ci.org/matterhorn-chat/mattermost-api)
+[![Build status](https://github.com/matterhorn-chat/mattermost-api/actions/workflows/ci.yml/badge.svg)](https://github.com/matterhorn-chat/mattermost-api/actions/workflows/ci.yml)
 # mattermost-api
 
 Client-side API for communicating with a Mattermost server, written in
diff --git a/mattermost-api.cabal b/mattermost-api.cabal
--- a/mattermost-api.cabal
+++ b/mattermost-api.cabal
@@ -1,5 +1,5 @@
 name:                mattermost-api
-version:             50200.11.0
+version:             50200.12.0
 synopsis:            Client API for Mattermost chat system
 
 description:         Client API for Mattermost chat system.  Mattermost is a
@@ -49,7 +49,7 @@
   build-depends:       base >=4.4 && <5
                      , websockets >= 0.11.0.0
                      , stm
-                     , aeson >= 1.0.0.0
+                     , aeson >= 2.0.1.0 && < 2.1.0.0
                      , connection
                      , memory
                      , resource-pool >= 0.2.3
diff --git a/src/Network/Mattermost.hs b/src/Network/Mattermost.hs
--- a/src/Network/Mattermost.hs
+++ b/src/Network/Mattermost.hs
@@ -140,6 +140,7 @@
 import           Network.HTTP.Stream ( simpleHTTP_ )
 import           Data.HashMap.Strict ( HashMap )
 import qualified Data.HashMap.Strict as HM
+import qualified Data.Aeson.KeyMap as KM
 import           Data.Aeson ( Value(..)
                             , ToJSON(..)
                             , FromJSON
@@ -1065,7 +1066,7 @@
                                               (show $ rspCode rsp)
         in case eitherDecode $ BL.pack $ rspBody rsp of
             Right (Object o) ->
-                case HM.lookup "message" o of
+                case KM.lookup "message" o of
                     Just (String msg) ->
                         let newMsg = (T.pack $ "Error requesting " <> show path <> ": ") <> msg
                         in throwIO $ MattermostServerError newMsg
diff --git a/src/Network/Mattermost/Proxy.hs b/src/Network/Mattermost/Proxy.hs
--- a/src/Network/Mattermost/Proxy.hs
+++ b/src/Network/Mattermost/Proxy.hs
@@ -36,12 +36,10 @@
                         go [] [] = True
                         go [] _ = False
                         go _ [] = False
-                        go (p:pParts) hParts =
+                        go (p:pParts) (h:hTail) =
                             if p == "*"
                             then True
-                            else case hParts of
-                                [] -> False
-                                (h:hTail) -> p == h && go pParts hTail
+                            else p == h && go pParts hTail
                     in go patParts hostnameParts
             return $ not isBlacklisted
 
diff --git a/src/Network/Mattermost/Types.hs b/src/Network/Mattermost/Types.hs
--- a/src/Network/Mattermost/Types.hs
+++ b/src/Network/Mattermost/Types.hs
@@ -120,11 +120,13 @@
 data Login
   = Login
   { username :: Text
+  , otpToken :: Maybe Text
   , password :: Text
   } deriving (Show)
 
 instance A.ToJSON Login where
   toJSON l = A.object ["login_id" A..= username l
+                      ,"token" A..= (fromMaybe "" $ otpToken l)
                       ,"password" A..= password l
                       ]
 
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -45,6 +45,7 @@
 testUserLogin = Login
   { username = "test-user"
   , password = "password"
+  , otpToken = Nothing
   }
 
 testMinChannel :: TeamId -> MinChannel
diff --git a/test/Tests/Util.hs b/test/Tests/Util.hs
--- a/test/Tests/Util.hs
+++ b/test/Tests/Util.hs
@@ -297,6 +297,7 @@
     cfg <- gets tsConfig
     let admin = Login { username = configUsername cfg
                       , password = configPassword cfg
+                      , otpToken = Nothing
                       }
     loginAccount admin
 
