diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+google-oauth2-jwt - Copyright Michel Boucey (c) 2016
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author Michel Boucey nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/google-oauth2-jwt.cabal b/google-oauth2-jwt.cabal
new file mode 100644
--- /dev/null
+++ b/google-oauth2-jwt.cabal
@@ -0,0 +1,32 @@
+name:                google-oauth2-jwt
+version:             0.1.0.0
+synopsis:            Get a signed JWT for Google Service Accounts
+description:         Please see README.md
+homepage:            https://github.com/MichelBoucey/google-oauth2-jwt
+license:             BSD3
+license-file:        LICENSE
+author:              Michel Boucey
+maintainer:          michel.boucey@gmail.com
+copyright:           Copyright (c) 2016 - Michel Boucey
+category:            Google
+build-type:          Simple
+-- extra-source-files:
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Network.Google.OAuth2.JWT
+  build-depends:       base >= 4.7 && < 5
+                     , base64-bytestring
+                     , bytestring
+                     , HsOpenSSL
+                     , RSA
+                     , text
+                     , unix-time
+  default-language:    Haskell2010
+  GHC-options:       -Wall
+
+source-repository head
+  type:     git
+  location: https://github.com/MichelBoucey/google-oauth2-jwt
+
diff --git a/src/Network/Google/OAuth2/JWT.hs b/src/Network/Google/OAuth2/JWT.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Google/OAuth2/JWT.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Create a signed JWT needed to make the access token request
+-- to gain access to Google APIs for server to server applications.
+--
+-- For all details : https://developers.google.com/identity/protocols/OAuth2ServiceAccount
+--
+
+module Network.Google.OAuth2.JWT where
+
+import           Codec.Crypto.RSA.Pure
+import qualified Data.ByteString            as B
+import           Data.ByteString.Base64.URL (encode)
+import           Data.ByteString.Lazy       (fromStrict, toStrict)
+import           Data.Maybe                 (fromJust)
+import           Data.Monoid                ((<>))
+import qualified Data.Text                  as T
+import           Data.Text.Encoding
+import           Data.UnixTime              (getUnixTime, utSeconds)
+import           Foreign.C.Types
+import           OpenSSL.EVP.PKey           (toKeyPair)
+import           OpenSSL.PEM                (PemPasswordSupply (PwNone),
+                                             readPrivateKey)
+import           OpenSSL.RSA
+
+type Scope = T.Text
+
+type Email = T.Text
+
+-- |Get the private key obtained from
+-- the Google API Console from a PEM file.
+fromPEMFile :: FilePath -> IO PrivateKey
+fromPEMFile f = readFile f >>= fromPEMString
+
+-- |Get the private key obtained from
+-- the Google API Console from a PEM 'String'.
+fromPEMString :: String -> IO PrivateKey
+fromPEMString s =
+    fromJust . toKeyPair <$> readPrivateKey s PwNone
+        >>= \k -> return $ PrivateKey
+            { private_pub =
+                  PublicKey { public_size = rsaSize k
+                            , public_n    = rsaN k
+                            , public_e    = rsaE k
+                            }
+            , private_d    = rsaD k
+            , private_p    = rsaP k
+            , private_q    = rsaQ k
+            , private_dP   = 0
+            , private_dQ   = 0
+            , private_qinv = 0
+            }
+
+-- | Create the signed JWT ready for transmission
+-- in the access token request as assertion value.
+--
+-- >grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=
+--
+getJWT :: Email
+       -- ^ The email address of the service account.
+       -> Maybe Email
+       -- ^ The email address of the user for which the
+       -- application is requesting delegated access.
+       -> [Scope]
+       -- ^The list of the permissions that the application requests.
+       -> Maybe Int
+       -- ^ Expiration time (maximun and default value is an hour, 3600).
+       -> PrivateKey
+       -- ^ The private key obtained from the Google API Console.
+       -> IO (Either String B.ByteString)
+       -- ^ Either an error message or a signed JWT.
+getJWT iss msub scopes mexp privateKey = do
+    let expt = fromIntegral $
+                  case mexp of
+                      Just e  -> e
+                      Nothing -> 3600
+    cs <- jwtClaimsSet
+              (maybe T.empty (\s -> "\"sub\":\"" <> s <> "\",") msub) expt
+    let i = jwtHeader <> "." <> cs
+    return $ do
+        if expt > 0 && expt <= 3600 then
+            case rsassa_pkcs1_v1_5_sign hashSHA256 privateKey (fromStrict i) of
+                Right s -> Right $ i <> "." <> (encode $ toStrict s)
+                Left _  -> Left "RSAError"
+                                    else Left "Bad expiration time"
+  where
+    jwtHeader = toJWT "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"
+    jwtClaimsSet s e = do
+        (exp',iat') <-
+            getUnixTime >>= \t ->
+                return ( toText $ utSeconds t + CTime e
+                       , toText $ utSeconds t
+                       )
+        return $ toJWT $
+               "{\"iss\":\"" <> iss <> "\"," <> s <> "\"scope\":\""
+            <> T.intercalate " " scopes <> "\",\"aud\":\"https://ww\
+               \w.googleapis.com/oauth2/v4/token\",\"exp\":" <> exp'
+            <> ",\"iat\":" <> iat' <> "}"
+    toText = (T.pack . show)
+    toJWT = (encode . encodeUtf8)
+
