diff --git a/Yesod/Helpers/Auth.hs b/Yesod/Helpers/Auth.hs
--- a/Yesod/Helpers/Auth.hs
+++ b/Yesod/Helpers/Auth.hs
@@ -21,10 +21,23 @@
     , requireAuth
     ) where
 
-import Yesod
+import Yesod.Handler
+import Yesod.Core
+import Yesod.Widget
+import Yesod.Content
+import Yesod.Dispatch
+import Yesod.Persist
+import Yesod.Request
+import Yesod.Json
+import Text.Blaze
 import Language.Haskell.TH.Syntax hiding (lift)
 import qualified Data.ByteString.Char8 as S8
 import qualified Network.Wai as W
+import Text.Hamlet (hamlet)
+import Data.Text.Lazy (pack)
+import Data.JSON.Types (Value (..), Atom (AtomBoolean))
+import qualified Data.Map as Map
+import Control.Monad.Trans.Class (lift)
 
 data Auth = Auth
 
@@ -69,9 +82,56 @@
     loginHandler :: GHandler Auth m RepHtml
     loginHandler = defaultLayout $ do
         setTitle $ string "Login"
-        tm <- liftHandler getRouteToMaster
+        tm <- lift getRouteToMaster
         mapM_ (flip apLogin tm) authPlugins
 
+    ----- Message strings. In theory in the future make this localizable
+    ----- See gist: https://gist.github.com/778712
+    messageNoOpenID :: m -> Html
+    messageNoOpenID _ = string "No OpenID identifier found"
+    messageLoginOpenID :: m -> Html
+    messageLoginOpenID _ = string "Login via OpenID"
+
+    messageEmail :: m -> Html
+    messageEmail _ = string "Email"
+    messagePassword :: m -> Html
+    messagePassword _ = string "Password"
+    messageRegister :: m -> Html
+    messageRegister _ = string "Register"
+    messageRegisterLong :: m -> Html
+    messageRegisterLong _ = string "Register a new account"
+    messageEnterEmail :: m -> Html
+    messageEnterEmail _ = string "Enter your e-mail address below, and a confirmation e-mail will be sent to you."
+    messageConfirmationEmailSentTitle :: m -> Html
+    messageConfirmationEmailSentTitle _ = string "Confirmation e-mail sent"
+    messageConfirmationEmailSent :: m -> String -> Html
+    messageConfirmationEmailSent _ email = string $ "A confirmation e-mail has been sent to " ++ email ++ "."
+    messageAddressVerified :: m -> Html
+    messageAddressVerified _ = string "Address verified, please set a new password"
+    messageInvalidKeyTitle :: m -> Html
+    messageInvalidKeyTitle _ = string "Invalid verification key"
+    messageInvalidKey :: m -> Html
+    messageInvalidKey _ = string "I'm sorry, but that was an invalid verification key."
+    messageInvalidEmailPass :: m -> Html
+    messageInvalidEmailPass _ = string "Invalid email/password combination"
+    messageBadSetPass :: m -> Html
+    messageBadSetPass _ = string "You must be logged in to set a password"
+    messageSetPassTitle :: m -> Html
+    messageSetPassTitle _ = string "Set password"
+    messageSetPass :: m -> Html
+    messageSetPass _ = string "Set a new password"
+    messageNewPass :: m -> Html
+    messageNewPass _ = string "New password"
+    messageConfirmPass :: m -> Html
+    messageConfirmPass _ = string "Confirm"
+    messagePassMismatch :: m -> Html
+    messagePassMismatch _ = string "Passwords did not match, please try again"
+    messagePassUpdated :: m -> Html
+    messagePassUpdated _ = string "Password updated"
+
+    messageFacebook :: m -> Html
+    messageFacebook _ = string "Login with Facebook"
+
 mkYesodSub "Auth"
     [ ClassP ''YesodAuth [VarT $ mkName "master"]
     ]
@@ -107,7 +167,8 @@
 #else
                                 [$hamlet|
 #endif
-                                %h1 Invalid login|]
+                                <h1>Invalid login
+|]
                             sendResponse rh
                         Just ar -> do
                             setMessage $ string "Invalid login"
@@ -134,15 +195,17 @@
 #else
         [$hamlet|
 #endif
-%h1 Authentication Status
-$maybe creds _
-    %p Logged in.
+<h1>Authentication Status
+$maybe _ <- creds
+    <p>Logged in.
 $nothing
-    %p Not logged in.
+    <p>Not logged in.
 |]
     json creds =
-        jsonMap
-            [ ("logged_in", jsonScalar $ maybe "false" (const "true") creds)
+        ValueObject $ Map.fromList
+            [ (pack "logged_in"
+              , ValueAtom $ AtomBoolean
+                          $ maybe False (const True) creds)
             ]
 
 getLoginR :: YesodAuth m => GHandler Auth m RepHtml
@@ -176,7 +239,7 @@
 
 maybeAuth :: ( YesodAuth m
              , Key val ~ AuthId m
-             , PersistBackend (YesodDB m (GHandler s m))
+             , PersistBackend (YesodDB m (GGHandler s m IO))
              , PersistEntity val
              , YesodPersist m
              ) => GHandler s m (Maybe (Key val, val))
@@ -195,7 +258,7 @@
 
 requireAuth :: ( YesodAuth m
                , Key val ~ AuthId m
-               , PersistBackend (YesodDB m (GHandler s m))
+               , PersistBackend (YesodDB m (GGHandler s m IO))
                , PersistEntity val
                , YesodPersist m
                ) => GHandler s m (Key val, val)
diff --git a/Yesod/Helpers/Auth/Dummy.hs b/Yesod/Helpers/Auth/Dummy.hs
--- a/Yesod/Helpers/Auth/Dummy.hs
+++ b/Yesod/Helpers/Auth/Dummy.hs
@@ -7,8 +7,10 @@
     ( authDummy
     ) where
 
-import Yesod
 import Yesod.Helpers.Auth
+import Yesod.Form (runFormPost', stringInput)
+import Yesod.Handler (notFound)
+import Text.Hamlet (hamlet)
 
 authDummy :: YesodAuth m => AuthPlugin m
 authDummy =
@@ -25,8 +27,8 @@
 #else
         [$hamlet|
 #endif
-%form!method=post!action=@authToMaster.url@
-    Your new identifier is: $
-    %input!type=text!name=ident
-    %input!type=submit!value="Dummy Login"
+<form method="post" action="@{authToMaster url}">
+    \Your new identifier is: 
+    <input type="text" name="ident">
+    <input type="submit" value="Dummy Login">
 |]
diff --git a/Yesod/Helpers/Auth/Email.hs b/Yesod/Helpers/Auth/Email.hs
--- a/Yesod/Helpers/Auth/Email.hs
+++ b/Yesod/Helpers/Auth/Email.hs
@@ -7,7 +7,6 @@
     , saltPass
     ) where
 
-import Yesod
 import Network.Mail.Mime (randomString)
 import Yesod.Helpers.Auth
 import System.Random
@@ -17,6 +16,15 @@
 import qualified Data.Text.Lazy as T
 import Data.Text.Lazy.Encoding (encodeUtf8)
 
+import Yesod.Form
+import Yesod.Handler
+import Yesod.Content
+import Yesod.Widget
+import Yesod.Core
+import Text.Hamlet (hamlet)
+import Control.Monad.IO.Class (liftIO)
+import Control.Monad.Trans.Class (lift)
+
 login, register, setpass :: AuthRoute
 login = PluginR "email" ["login"]
 register = PluginR "email" ["register"]
@@ -63,26 +71,27 @@
 
 authEmail :: YesodAuthEmail m => AuthPlugin m
 authEmail =
-    AuthPlugin "email" dispatch $ \tm ->
+    AuthPlugin "email" dispatch $ \tm -> do
+        y <- lift getYesod
 #if GHC7
         [hamlet|
 #else
         [$hamlet|
 #endif
-%form!method=post!action=@tm.login@
-    %table
-        %tr
-            %th E-mail
-            %td
-                %input!type=email!name=email
-        %tr
-            %th Password
-            %td
-                %input!type=password!name=password
-        %tr
-            %td!colspan=2
-                %input!type=submit!value="Login via email"
-                %a!href=@tm.register@ I don't have an account
+<form method="post" action="@{tm login}">
+    <table>
+        <tr>
+            <th>#{messageEmail y}
+            <td>
+                <input type="email" name="email">
+        <tr>
+            <th>#{messagePassword y}
+            <td>
+                <input type="password" name="password">
+        <tr>
+            <td colspan="2">
+                <input type="submit" value="Login via email">
+                <a href="@{tm register}">I don't have an account
 |]
   where
     dispatch "GET" ["register"] = getRegisterR >>= sendResponse
@@ -99,20 +108,21 @@
 
 getRegisterR :: YesodAuthEmail master => GHandler Auth master RepHtml
 getRegisterR = do
+    y <- getYesod
     toMaster <- getRouteToMaster
     defaultLayout $ do
-        setTitle $ string "Register a new account"
+        setTitle $ messageRegisterLong y
         addHamlet
 #if GHC7
             [hamlet|
 #else
             [$hamlet|
 #endif
-%p Enter your e-mail address below, and a confirmation e-mail will be sent to you.
-%form!method=post!action=@toMaster.register@
-    %label!for=email E-mail
-    %input!type=email!name=email!width=150
-    %input!type=submit!value=Register
+<p>#{messageEnterEmail y}
+<form method="post" action="@{toMaster register}">
+    <label for="email">#{messageEmail y}
+    <input type="email" name="email" width="150">
+    <input type="submit" value="#{messageRegister y}">
 |]
 
 postRegisterR :: YesodAuthEmail master => GHandler Auth master RepHtml
@@ -136,14 +146,14 @@
     let verUrl = render $ tm $ verify (showAuthEmailId y lid) verKey
     sendVerifyEmail email verKey verUrl
     defaultLayout $ do
-        setTitle $ string "Confirmation e-mail sent"
+        setTitle $ messageConfirmationEmailSentTitle y
         addWidget
 #if GHC7
             [hamlet|
 #else
             [$hamlet|
 #endif
-%p A confirmation e-mail has been sent to $email$.
+<p>#{messageConfirmationEmailSent y email}
 |]
 
 getVerifyR :: YesodAuthEmail m
@@ -151,6 +161,7 @@
 getVerifyR lid key = do
     realKey <- getVerifyKey lid
     memail <- getEmail lid
+    y <- getYesod
     case (realKey == Just key, memail) of
         (True, Just email) -> do
             muid <- verifyAccount lid
@@ -159,18 +170,18 @@
                 Just _uid -> do
                     setCreds False $ Creds "email" email [("verifiedEmail", email)] -- FIXME uid?
                     toMaster <- getRouteToMaster
-                    setMessage $ string "Address verified, please set a new password"
+                    setMessage $ messageAddressVerified y
                     redirect RedirectTemporary $ toMaster setpass
         _ -> return ()
     defaultLayout $ do
-        setTitle $ string "Invalid verification key"
+        setTitle $ messageInvalidKey y
         addHtml
 #if GHC7
             [hamlet|
 #else
             [$hamlet|
 #endif
-%p I'm sorry, but that was an invalid verification key.
+<p>#{messageInvalidKey y}
 |]
 
 postLoginR :: YesodAuthEmail master => GHandler Auth master ()
@@ -194,7 +205,8 @@
         Just _aid ->
             setCreds True $ Creds "email" email [("verifiedEmail", email)] -- FIXME aid?
         Nothing -> do
-            setMessage $ string "Invalid email/password combination"
+            y <- getYesod
+            setMessage $ messageInvalidEmailPass y
             toMaster <- getRouteToMaster
             redirect RedirectTemporary $ toMaster LoginR
 
@@ -202,33 +214,34 @@
 getPasswordR = do
     toMaster <- getRouteToMaster
     maid <- maybeAuthId
+    y <- getYesod
     case maid of
         Just _ -> return ()
         Nothing -> do
-            setMessage $ string "You must be logged in to set a password"
+            setMessage $ messageBadSetPass y
             redirect RedirectTemporary $ toMaster login
     defaultLayout $ do
-        setTitle $ string "Set password"
+        setTitle $ messageSetPassTitle y
         addHamlet
 #if GHC7
             [hamlet|
 #else
             [$hamlet|
 #endif
-%h3 Set a new password
-%form!method=post!action=@toMaster.setpass@
-    %table
-        %tr
-            %th New password
-            %td
-                %input!type=password!name=new
-        %tr
-            %th Confirm
-            %td
-                %input!type=password!name=confirm
-        %tr
-            %td!colspan=2
-                %input!type=submit!value=Submit
+<h3>#{messageSetPass y}
+<form method="post" action="@{toMaster setpass}">
+    <table>
+        <tr>
+            <th>#{messageNewPass y}
+            <td>
+                <input type="password" name="new">
+        <tr>
+            <th>#{messageConfirmPass y}
+            <td>
+                <input type="password" name="confirm">
+        <tr>
+            <td colspan="2">
+                <input type="submit" value="#{messageSetPassTitle y}">
 |]
 
 postPasswordR :: YesodAuthEmail master => GHandler Auth master ()
@@ -237,19 +250,19 @@
         <$> stringInput "new"
         <*> stringInput "confirm"
     toMaster <- getRouteToMaster
+    y <- getYesod
     when (new /= confirm) $ do
-        setMessage $ string "Passwords did not match, please try again"
+        setMessage $ messagePassMismatch y
         redirect RedirectTemporary $ toMaster setpass
     maid <- maybeAuthId
     aid <- case maid of
             Nothing -> do
-                setMessage $ string "You must be logged in to set a password"
+                setMessage $ messageBadSetPass y
                 redirect RedirectTemporary $ toMaster login
             Just aid -> return aid
     salted <- liftIO $ saltPass new
     setPassword aid salted
-    setMessage $ string "Password updated"
-    y <- getYesod
+    setMessage $ messagePassUpdated y
     redirect RedirectTemporary $ loginDest y
 
 saltLength :: Int
diff --git a/Yesod/Helpers/Auth/Facebook.hs b/Yesod/Helpers/Auth/Facebook.hs
--- a/Yesod/Helpers/Auth/Facebook.hs
+++ b/Yesod/Helpers/Auth/Facebook.hs
@@ -5,12 +5,19 @@
     , facebookUrl
     ) where
 
-import Yesod
 import Yesod.Helpers.Auth
 import qualified Web.Authenticate.Facebook as Facebook
 import Data.Object (fromMapping, lookupScalar)
 import Data.Maybe (fromMaybe)
 
+import Yesod.Form
+import Yesod.Handler
+import Yesod.Widget
+import Text.Hamlet (hamlet)
+import Control.Monad.IO.Class (liftIO)
+import qualified Data.ByteString.Char8 as S8
+import Control.Monad.Trans.Class (lift)
+
 facebookUrl :: AuthRoute
 facebookUrl = PluginR "facebook" ["forward"]
 
@@ -27,7 +34,7 @@
         tm <- getRouteToMaster
         render <- getUrlRender
         let fb = Facebook.Facebook cid secret $ render $ tm url
-        redirectString RedirectTemporary $ Facebook.getForwardUrl fb perms
+        redirectString RedirectTemporary $ S8.pack $ Facebook.getForwardUrl fb perms
     dispatch "GET" [] = do
         render <- getUrlRender
         tm <- getRouteToMaster
@@ -51,15 +58,16 @@
         setCreds True c
     dispatch _ _ = notFound
     login tm = do
-        render <- liftHandler getUrlRender
+        render <- lift getUrlRender
         let fb = Facebook.Facebook cid secret $ render $ tm url
         let furl = Facebook.getForwardUrl fb $ perms
+        y <- lift getYesod
         addHtml
 #if GHC7
             [hamlet|
 #else
             [$hamlet|
 #endif
-%p
-    %a!href=$furl$ Login with Facebook
+<p>
+    <a href="#{furl}">#{messageFacebook y}
 |]
diff --git a/Yesod/Helpers/Auth/HashDB.hs b/Yesod/Helpers/Auth/HashDB.hs
new file mode 100644
--- /dev/null
+++ b/Yesod/Helpers/Auth/HashDB.hs
@@ -0,0 +1,206 @@
+{-# LANGUAGE QuasiQuotes                #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE TemplateHaskell            #-}
+-------------------------------------------------------------------------------
+-- |
+-- Module      :  Yesod.Helpers.Auth.HashDB
+-- Copyright   :  (c) Patrick Brisbin 2010 
+-- License     :  as-is
+--
+-- Maintainer  :  pbrisbin@gmail.com
+-- Stability   :  Stable
+-- Portability :  Portable
+--
+-- A yesod-auth AuthPlugin designed to look users up in Persist where
+-- their user id's and a sha1 hash of their password will already be
+-- stored.
+--
+-- Example usage:
+--
+-- > -- import the function
+-- > import Helpers.Auth.HashDB
+-- >
+-- > -- make sure you have an auth route
+-- > mkYesodData "MyApp" [$parseRoutes|
+-- > / RootR GET
+-- > /auth AuthR Auth getAuth
+-- > |]
+-- >
+-- >
+-- > -- make your app an instance of YesodAuth using this plugin
+-- > instance YesodAuth MyApp where
+-- >    type AuthId MyApp = UserId
+-- >
+-- >    loginDest _  = RootR
+-- >    logoutDest _ = RootR
+-- >    getAuthId    = getAuthIdHashDB AuthR 
+-- >    showAuthId _ = showIntegral
+-- >    readAuthId _ = readIntegral
+-- >    authPlugins  = [authHashDB]
+-- >
+-- >
+-- > -- include the migration function in site startup
+-- > withServer :: (Application -> IO a) -> IO a
+-- > withServer f = withConnectionPool $ \p -> do
+-- >     runSqlPool (runMigration migrateUsers) p
+-- >     let h = DevSite p
+--
+-- Your app must be an instance of YesodPersist and the username and
+-- hashed-passwords must be added manually to the database.
+--
+-- > echo -n 'MyPassword' | sha1sum
+--
+-- can be used to get the hash from the commandline.
+--
+-------------------------------------------------------------------------------
+module Yesod.Helpers.Auth.HashDB
+    ( authHashDB
+    , getAuthIdHashDB
+    , UserId
+    , migrateUsers
+    ) where
+
+import Yesod.Persist
+import Yesod.Handler
+import Yesod.Form
+import Yesod.Helpers.Auth
+import Text.Hamlet (hamlet)
+
+import Control.Applicative         ((<$>), (<*>))
+import Data.ByteString.Lazy.Char8  (pack)
+import Data.Digest.Pure.SHA        (sha1, showDigest)
+import Database.Persist.TH         (share2)
+import Database.Persist.GenericSql (mkMigrate)
+
+-- | Computer the sha1 of a string and return it as a string
+sha1String :: String -> String
+sha1String = showDigest . sha1 . pack
+
+-- | Generate data base instances for a valid user
+share2 mkPersist (mkMigrate "migrateUsers")
+#if GHC7
+            [persist|
+#else
+            [$persist|
+#endif
+User
+    username String Eq
+    password String
+    UniqueUser username
+|]
+
+-- | Given a (user,password) in plaintext, validate them against the
+--   database values
+validateUser :: (YesodPersist y, 
+                 PersistBackend (YesodDB y (GGHandler sub y IO))) 
+             => (String, String) 
+             -> GHandler sub y Bool
+validateUser (user,password) = runDB (getBy $ UniqueUser user) >>= \dbUser ->
+    case dbUser of
+        -- user not found
+        Nothing          -> return False
+        -- validate password
+        Just (_, sqlUser) -> return $ sha1String password == userPassword sqlUser
+
+login :: AuthRoute
+login = PluginR "hashdb" ["login"]
+
+-- | Handle the login form
+postLoginR :: (YesodAuth y,
+               YesodPersist y, 
+               PersistBackend (YesodDB y (GGHandler Auth y IO)))
+           => GHandler Auth y ()
+postLoginR = do
+    (user, password) <- runFormPost' $ (,)
+        <$> stringInput "username"
+        <*> stringInput "password"
+
+    isValid <- validateUser (user,password)
+
+    if isValid
+        then setCreds True $ Creds "hashdb" user []
+        else do
+            setMessage
+#if GHC7
+                [hamlet|
+#else
+                [$hamlet|
+#endif
+    <em>invalid username/password
+|]
+            toMaster <- getRouteToMaster
+            redirect RedirectTemporary $ toMaster LoginR
+
+-- | A drop in for the getAuthId method of your YesodAuth instance which
+--   can be used if authHashDB is the only plugin in use.
+getAuthIdHashDB :: (Key User ~ AuthId master,
+                    PersistBackend (YesodDB master (GGHandler sub master IO)),
+                    YesodPersist master,
+                    YesodAuth master)
+                => (AuthRoute -> Route master) -- ^ your site's Auth Route
+                -> Creds m                     -- ^ the creds argument
+                -> GHandler sub master (Maybe UserId)
+getAuthIdHashDB authR creds = do
+    muid <- maybeAuth
+    case muid of
+        -- user already authenticated
+        Just (uid, _) -> return $ Just uid
+        Nothing       -> do
+            x <- runDB $ getBy $ UniqueUser (credsIdent creds)
+            case x of
+                -- user exists
+                Just (uid, _) -> return $ Just uid
+                Nothing       -> do
+                    setMessage
+#if GHC7
+                        [hamlet|
+#else
+                        [$hamlet|
+#endif
+    <em>user not found
+|]
+                    redirect RedirectTemporary $ authR LoginR
+
+-- | Prompt for username and password, validate that against a database
+--   which holds the username and a hash of the password
+authHashDB :: (YesodAuth y,
+               YesodPersist y, 
+               PersistBackend (YesodDB y (GGHandler Auth y IO)))
+           => AuthPlugin y
+authHashDB = AuthPlugin "hashdb" dispatch $ \tm ->
+#if GHC7
+    [hamlet|
+#else
+    [$hamlet|
+#endif
+    <div id="header">
+        <h1>Login
+\
+    <div id="login">
+        <form method="post" action="@{tm login}">
+            <table>
+                <tr>
+                    <th>Username:
+                    <td>
+                        <input id="x" name="username" autofocus="">
+                <tr>
+                    <th>Password:
+                    <td>
+                        <input type="password" name="password">
+                <tr>
+                    <td>&nbsp;
+                    <td>
+                        <input type="submit" value="Login">
+\
+            <script>
+                \if (!("autofocus" in document.createElement("input"))) {
+                    \document.getElementById("x").focus();
+                \}
+    \
+|]
+    where
+        dispatch "POST" ["login"] = postLoginR >>= sendResponse
+        dispatch _ _              = notFound
diff --git a/Yesod/Helpers/Auth/OpenId.hs b/Yesod/Helpers/Auth/OpenId.hs
--- a/Yesod/Helpers/Auth/OpenId.hs
+++ b/Yesod/Helpers/Auth/OpenId.hs
@@ -5,11 +5,20 @@
     , forwardUrl
     ) where
 
-import Yesod
 import Yesod.Helpers.Auth
 import qualified Web.Authenticate.OpenId as OpenId
 import Control.Monad.Attempt
 
+import Yesod.Form
+import Yesod.Handler
+import Yesod.Widget
+import Yesod.Request
+import Text.Hamlet (hamlet)
+import Text.Cassius (cassius)
+import Text.Blaze (string)
+import Control.Monad.Trans.Class (lift)
+import qualified Data.ByteString.Char8 as S8
+
 forwardUrl :: AuthRoute
 forwardUrl = PluginR "openid" ["forward"]
 
@@ -17,17 +26,17 @@
 authOpenId =
     AuthPlugin "openid" dispatch login
   where
-    complete = PluginR "openid" ["complete"]
+    complete = PluginR "openid" ["complete", ""]
     name = "openid_identifier"
     login tm = do
-        ident <- newIdent
+        ident <- lift newIdent
+        y <- lift getYesod
         addCassius
 #if GHC7
-            [cassius|
+            [cassius|##{ident}
 #else
-            [$cassius|
+            [$cassius|##{ident}
 #endif
-  #$ident$
     background: #fff url(http://www.myopenid.com/static/openid-icon-small.gif) no-repeat scroll 0pt 50%;
     padding-left: 18px;
 |]
@@ -37,36 +46,36 @@
 #else
             [$hamlet|
 #endif
-%form!method=get!action=@tm.forwardUrl@
-    %label!for=openid OpenID: $
-    %input#$ident$!type=text!name=$name$!value="http://"
-    %input!type=submit!value="Login via OpenID"
+<form method="get" action="@{tm forwardUrl}">
+    <label for="#{ident}">OpenID: 
+    <input id="#{ident}" type="text" name="#{name}" value="http://">
+    <input type="submit" value="#{messageLoginOpenID y}">
 |]
     dispatch "GET" ["forward"] = do
         (roid, _, _) <- runFormGet $ stringInput name
+        y <- getYesod
         case roid of
             FormSuccess oid -> do
                 render <- getUrlRender
                 toMaster <- getRouteToMaster
                 let complete' = render $ toMaster complete
-                res <- runAttemptT $ OpenId.getForwardUrl oid complete'
+                res <- runAttemptT $ OpenId.getForwardUrl oid complete' Nothing []
                 attempt
                   (\err -> do
                         setMessage $ string $ show err
                         redirect RedirectTemporary $ toMaster LoginR
                         )
-                  (redirectString RedirectTemporary)
+                  (redirectString RedirectTemporary . S8.pack)
                   res
             _ -> do
                 toMaster <- getRouteToMaster
-                setMessage $ string "No OpenID identifier found"
+                setMessage $ messageNoOpenID y
                 redirect RedirectTemporary $ toMaster LoginR
-    dispatch "GET" ["complete"] = do
+    dispatch "GET" ["complete", ""] = do
         rr <- getRequest
         completeHelper $ reqGetParams rr
-    dispatch "POST" ["complete"] = do
-        rr <- getRequest
-        (posts, _) <- liftIO $ reqRequestBody rr
+    dispatch "POST" ["complete", ""] = do
+        (posts, _) <- runRequestBody
         completeHelper posts
     dispatch _ _ = notFound
 
@@ -77,6 +86,6 @@
         let onFailure err = do
             setMessage $ string $ show err
             redirect RedirectTemporary $ toMaster LoginR
-        let onSuccess (OpenId.Identifier ident) =
+        let onSuccess (OpenId.Identifier ident, _) =
                 setCreds True $ Creds "openid" ident []
         attempt onFailure onSuccess res
diff --git a/Yesod/Helpers/Auth/Rpxnow.hs b/Yesod/Helpers/Auth/Rpxnow.hs
--- a/Yesod/Helpers/Auth/Rpxnow.hs
+++ b/Yesod/Helpers/Auth/Rpxnow.hs
@@ -4,11 +4,16 @@
     ( authRpxnow
     ) where
 
-import Yesod
 import Yesod.Helpers.Auth
 import qualified Web.Authenticate.Rpxnow as Rpxnow
 import Control.Monad (mplus)
 
+import Yesod.Handler
+import Yesod.Widget
+import Yesod.Request
+import Text.Hamlet (hamlet)
+import Control.Monad.IO.Class (liftIO)
+
 authRpxnow :: YesodAuth m
            => String -- ^ app name
            -> String -- ^ key
@@ -24,7 +29,7 @@
 #else
             [$hamlet|
 #endif
-%iframe!src="http://$app$.rpxnow.com/openid/embed?token_url=@url@"!scrolling=no!frameBorder=no!allowtransparency=true!style="width:400px;height:240px"
+<iframe src="http://#{app}.rpxnow.com/openid/embed?token_url=@{url}" scrolling="no" frameBorder="no" allowtransparency="true" style="width:400px;height:240px">
 |]
     dispatch _ [] = do
         token1 <- lookupGetParam "token"
diff --git a/yesod-auth.cabal b/yesod-auth.cabal
--- a/yesod-auth.cabal
+++ b/yesod-auth.cabal
@@ -1,13 +1,13 @@
 name:            yesod-auth
-version:         0.2.0.3
+version:         0.3.0
 license:         BSD3
 license-file:    LICENSE
-author:          Michael Snoyman <michael@snoyman.com>
+author:          Michael Snoyman, Patrick Brisbin
 maintainer:      Michael Snoyman <michael@snoyman.com>
 synopsis:        Authentication for Yesod.
-category:        Web
+category:        Web, Yesod
 stability:       Stable
-cabal-version:   >= 1.6
+cabal-version:   >= 1.6.0
 build-type:      Simple
 homepage:        http://docs.yesodweb.com/
 
@@ -19,23 +19,35 @@
         cpp-options:     -DGHC7
     else
         build-depends:   base                      >= 4        && < 4.3
-    build-depends:   authenticate            >= 0.7       && < 0.8
+    build-depends:   authenticate            >= 0.8       && < 0.9
                    , bytestring              >= 0.9.1.4   && < 0.10
-                   , yesod                   >= 0.6       && < 0.7
-                   , wai                     >= 0.2       && < 0.3
+                   , yesod-core              >= 0.7       && < 0.8
+                   , wai                     >= 0.3       && < 0.4
                    , template-haskell
                    , pureMD5                 >= 1.1       && < 2.2
                    , random                  >= 1.0       && < 1.1
                    , data-object             >= 0.3.1.3   && < 0.4
                    , control-monad-attempt   >= 0.3.0     && < 0.4
                    , text                    >= 0.7       && < 0.12
-                   , mime-mail               >= 0.0       && < 0.1
+                   , mime-mail               >= 0.1       && < 0.2
+                   , blaze-html              >= 0.4       && < 0.5
+                   , yesod-persistent        >= 0.0       && < 0.1
+                   , hamlet                  >= 0.7       && < 0.8
+                   , yesod-json              >= 0.0       && < 0.1
+                   , containers              >= 0.2       && < 0.5
+                   , json-types              >= 0.1       && < 0.2
+                   , text                    >= 0.11      && < 0.12
+                   , yesod-form              >= 0.0       && < 0.1
+                   , transformers            >= 0.2       && < 0.3
+                   , persistent              >= 0.4       && < 0.5
+                   , SHA                     >= 1.4.1.3   && < 1.5
     exposed-modules: Yesod.Helpers.Auth
                      Yesod.Helpers.Auth.Dummy
                      Yesod.Helpers.Auth.Email
                      Yesod.Helpers.Auth.Facebook
                      Yesod.Helpers.Auth.OpenId
                      Yesod.Helpers.Auth.Rpxnow
+                     Yesod.Helpers.Auth.HashDB
     ghc-options:     -Wall
 
 source-repository head
