diff --git a/bin/generate.hs b/bin/generate.hs
new file mode 100644
--- /dev/null
+++ b/bin/generate.hs
@@ -0,0 +1,9 @@
+module Main where
+
+import Data.Maybe (fromMaybe, listToMaybe)
+import Control.Monad (void)
+import System.Environment (getArgs)
+import Web.ClientSession (randomKeyEnv)
+
+main :: IO ()
+main = void $ randomKeyEnv . fromMaybe "SESSION_KEY" . listToMaybe =<< getArgs
diff --git a/clientsession.cabal b/clientsession.cabal
--- a/clientsession.cabal
+++ b/clientsession.cabal
@@ -1,5 +1,5 @@
 name:            clientsession
-version:         0.9.0.5
+version:         0.9.1
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>, Felipe Lessa <felipe.lessa@gmail.com>
@@ -20,6 +20,13 @@
   description: Build the executable to run unit tests
   default: False
 
+executable clientsession-generate
+    main-is: generate.hs
+    build-depends:   base
+                   , clientsession
+    ghc-options:     -Wall
+    hs-source-dirs: bin
+
 library
     build-depends:   base                >=4           && < 5
                    , bytestring          >= 0.9
@@ -33,7 +40,9 @@
                    , cprng-aes           >= 0.2
                    , cipher-aes          >= 0.1.7
                    , crypto-random
+                   , setenv
     exposed-modules: Web.ClientSession
+    other-modules:   System.LookupEnv
     ghc-options:     -Wall
     hs-source-dirs:  src
 
diff --git a/src/System/LookupEnv.hs b/src/System/LookupEnv.hs
new file mode 100644
--- /dev/null
+++ b/src/System/LookupEnv.hs
@@ -0,0 +1,6 @@
+module System.LookupEnv (lookupEnv) where
+
+import System.Environment (getEnvironment)
+
+lookupEnv :: String -> IO (Maybe String)
+lookupEnv envVar = fmap (lookup envVar) $ getEnvironment
diff --git a/src/Web/ClientSession.hs b/src/Web/ClientSession.hs
--- a/src/Web/ClientSession.hs
+++ b/src/Web/ClientSession.hs
@@ -45,10 +45,12 @@
     , randomIV
     , mkIV
     , getKey
+    , getKeyEnv
     , defaultKeyFile
     , getDefaultKey
     , initKey
     , randomKey
+    , randomKeyEnv
       -- * Actual encryption/decryption
     , encrypt
     , encryptIO
@@ -60,6 +62,17 @@
 import Control.Concurrent (forkIO)
 import Control.Monad (guard, when)
 import Data.Function (on)
+
+#if MIN_VERSION_base(4,7,0)
+import System.Environment (lookupEnv, setEnv)
+#elif MIN_VERSION_base(4,6,0)
+import System.Environment (lookupEnv)
+import System.SetEnv (setEnv)
+#else
+import System.LookupEnv (lookupEnv)
+import System.SetEnv (setEnv)
+#endif
+
 import System.IO.Unsafe (unsafePerformIO)
 import qualified Data.IORef as I
 
@@ -68,6 +81,7 @@
 
 -- from bytestring
 import qualified Data.ByteString as S
+import qualified Data.ByteString.Char8 as C
 import qualified Data.ByteString.Base64 as B
 
 -- from cereal
@@ -195,6 +209,22 @@
         S.writeFile keyFile bs
         return key'
 
+-- | Get the key from the named environment variable
+--
+-- Assumes the value is a Base64-encoded string. If the variable is not set, a
+-- random key will be generated, set in the environment, and the Base64-encoded
+-- version printed on @/dev/stdout@.
+getKeyEnv :: String     -- ^ Name of the environment variable
+          -> IO Key     -- ^ The actual key.
+getKeyEnv envVar = do
+    mvalue <- lookupEnv envVar
+    case mvalue of
+        Just value -> either (const newKey) return $ initKey =<< decode value
+        Nothing -> newKey
+  where
+    decode = B.decode . C.pack
+    newKey = randomKeyEnv envVar
+
 -- | Generate a random 'Key'.  Besides the 'Key', the
 -- 'ByteString' passed to 'initKey' is returned so that it can be
 -- saved for later use.
@@ -204,6 +234,17 @@
     case initKey bs of
         Left e -> error $ "Web.ClientSession.randomKey: never here, " ++ e
         Right key -> return (bs, key)
+
+-- | Generate a random 'Key', set a Base64-encoded version of it in the given
+-- environment variable, then return it. Also prints the generated string to
+-- @/dev/stdout@.
+randomKeyEnv :: String -> IO Key
+randomKeyEnv envVar = do
+    (bs, key) <- randomKey
+    let encoded = C.unpack $ B.encode bs
+    setEnv envVar encoded
+    putStrLn $ envVar ++ "=" ++ encoded
+    return key
 
 -- | Initializes a 'Key' from a random 'S.ByteString'.  Fails if
 -- there isn't exactly 96 bytes (256 bits for AES and 512 bits
diff --git a/tests/runtests.hs b/tests/runtests.hs
--- a/tests/runtests.hs
+++ b/tests/runtests.hs
@@ -22,6 +22,7 @@
 main :: IO ()
 main = hspec $ describe "client session" $ do
     it "encrypt/decrypt success" $ property propEncDec
+    it "encrypt/decrypt success (environment key)" $ property propEncDecEnv
     it "encrypt/decrypt failure" $ property propEncDecFailure
     it "AES encrypt/decrypt success" $ property propAES
     it "AES encryption changes bs" $ property propAESChanges
@@ -32,6 +33,13 @@
 propEncDec :: S.ByteString -> Bool
 propEncDec bs = unsafePerformIO $ do
     key <- getDefaultKey
+    s <- encryptIO key bs
+    let bs' = decrypt key s
+    return $ Just bs == bs'
+
+propEncDecEnv :: S.ByteString -> Bool
+propEncDecEnv bs = unsafePerformIO $ do
+    key <- getKeyEnv "SESSION_KEY"
     s <- encryptIO key bs
     let bs' = decrypt key s
     return $ Just bs == bs'
