diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2017, Herbert Valerio Riedel
+
+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  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/base-encoding.cabal b/base-encoding.cabal
new file mode 100644
--- /dev/null
+++ b/base-encoding.cabal
@@ -0,0 +1,55 @@
+cabal-version:       1.12
+name:                base-encoding
+version:             0.1.0.0
+
+synopsis:            Binary-to-text encodings (e.g. base64)
+license:             BSD3
+license-file:        LICENSE
+author:              Herbert Valerio Riedel
+bug-reports:         https://github.com/hvr/base-encoding/issues
+maintainer:          hvr@gnu.org
+category:            Text
+build-type:          Simple
+description:
+  This package provides a simple and convenient API to encode and
+  decode binary data in the popular binary-to-text \"base\" encoding
+  family as described in [RFC 4648](https://tools.ietf.org/html/rfc4648) et al.
+  .
+  Currently, the following encodings are supported:
+  .
+  - base16 (RFC4648)
+  - base64 (RFC4648)
+  - base64url (RFC4648)
+
+source-repository head
+  type:     git
+  location: https://github.com/hvr/base-encoding
+
+library
+  hs-source-dirs:      src
+
+  exposed-modules:
+    Codec.Base16
+    Codec.Base64
+    Codec.Base64Url
+
+  other-modules:
+    Internal
+
+  default-language:    Haskell2010
+  other-extensions:    CPP MultiParamTypeClasses
+
+  if impl(ghc >= 7.4)
+    default-extensions: Trustworthy
+    if impl(ghc >= 7.10)
+      ghc-options: -fno-warn-trustworthy-safe
+
+  build-depends:
+      base               >=4.3      && <4.12
+    , base16-bytestring  >=0.1.1.6  && <0.2
+    , base64-bytestring  >=1.0.0.1  && <1.1
+
+    , bytestring         >=0.9.1    && <0.11
+    , text               >=1.2.3    && <1.3
+
+  ghc-options: -Wall
diff --git a/src/Codec/Base16.hs b/src/Codec/Base16.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Base16.hs
@@ -0,0 +1,325 @@
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+-- | This module provides access to the \"base16\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).
+--
+-- This module is intended to be imported @qualified@, e.g.
+--
+-- > import qualified Codec.Base16 as B16
+--
+-- If you want to explictly specify which 'Encode' and 'Decode' typeclass instance is used, you can use plain Haskell2010 type-signature annotations, e.g.
+--
+-- >>> (B16.encode :: ByteString -> Text) "\202\254"
+-- "cafe"
+--
+-- >>> (B16.decode :: Text -> Either String ShortByteString) "CaFe"
+-- Right "\202\254"
+--
+-- Alternatively, starting with GHC 8.0.1, you can also use the [TypeApplications language extension](https://downloads.haskell.org/~ghc/8.4.1/docs/html/users_guide/glasgow_exts.html#ghc-flag--XTypeApplications):
+--
+-- >>> B16.encode @ShortByteString @Text "\xFF\239\0"
+-- "ffef00"
+--
+-- >>> B16.decode @Text @ShortByteString ""
+-- Right ""
+--
+-- @since 0.1.0.0
+module Codec.Base16
+    ( Encode(encode)
+    , Decode(decode)
+    ) where
+
+import qualified Data.ByteString.Base16       as B16
+import qualified Data.ByteString.Base16.Lazy  as B16.L
+
+import qualified Data.ByteString              as BS
+#if MIN_VERSION_bytestring(0,10,2)
+import qualified Data.ByteString.Builder      as BB
+#elif MIN_VERSION_bytestring(0,10,0)
+import qualified Data.ByteString.Lazy.Builder as BB
+#endif
+import qualified Data.ByteString.Lazy         as BS.L
+#if MIN_VERSION_bytestring(0,10,4)
+import qualified Data.ByteString.Short        as SBS
+#endif
+
+import qualified Data.Text                    as T (Text)
+import qualified Data.Text.Encoding           as T (decodeLatin1, encodeUtf8)
+import qualified Data.Text.Lazy               as T.L (Text, fromStrict)
+import qualified Data.Text.Lazy.Builder       as TB (Builder, fromLazyText,
+                                                     fromText, toLazyText)
+import qualified Data.Text.Lazy.Encoding      as T.L (decodeLatin1, encodeUtf8)
+
+import           Internal
+
+-- primitives
+
+decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString
+decodeBs2Bs txt
+  | BS.null rest = Right $! b
+  | otherwise    = Left ("invalid base16 encoding near offset " ++ show (2 * BS.length b))
+  where
+    (b,rest) = B16.decode txt
+
+decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString
+decodeBsL2BsL txt
+  | BS.L.null rest = Right $! b
+  | otherwise      = Left ("invalid base16 encoding near offset " ++ show (2 * BS.L.length b))
+  where
+    (b,rest) = B16.L.decode txt
+
+encodeBs2Bs :: BS.ByteString -> BS.ByteString
+encodeBs2Bs = B16.encode
+
+encodeBsL2BsL :: BS.L.ByteString -> BS.L.ByteString
+encodeBsL2BsL = B16.L.encode
+
+----------------------------------------------------------------------------
+-- exposed API
+
+-- | Typeclass representing types for which a binary-to-text @base16@ encoding is defined
+class Encode bin txt where
+  -- | Encode binary data using @base16@ text encoding
+  encode :: bin -> txt
+
+-- | Typeclass representing types for which a text-to-binary @base16@ decoding is defined
+class Decode txt bin where
+  -- | Decode binary data encoded textually as @base16@
+  decode :: txt -> Either String bin
+
+----------------------------------------------------------------------------
+-- instance matrix
+
+---- lazy BS -> *
+
+-- PRIMITIVE
+instance Encode BS.L.ByteString BS.L.ByteString where
+  encode = encodeBsL2BsL
+
+instance Encode BS.L.ByteString BS.ByteString where
+  encode = bsToStrict . encode
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BS.L.ByteString BB.Builder where
+  encode = BB.lazyByteString . encode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BS.L.ByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode
+#endif
+
+instance Encode BS.L.ByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BS.L.ByteString T.L.Text where
+  encode = T.L.decodeLatin1 . encode
+
+instance Encode BS.L.ByteString TB.Builder where
+  encode = TB.fromLazyText . encode
+
+---- strict BS  -> *
+
+-- PRIMITIVE
+instance Encode BS.ByteString BS.ByteString where
+  encode = encodeBs2Bs
+
+instance Encode BS.ByteString BS.L.ByteString where
+  encode = bsFromStrict . encode
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BS.ByteString BB.Builder where
+  encode = BB.byteString . encode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BS.ByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode
+#endif
+
+instance Encode BS.ByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BS.ByteString T.L.Text where
+  encode = T.L.fromStrict . T.decodeLatin1 . encode
+
+instance Encode BS.ByteString TB.Builder where
+  encode = TB.fromText . encode
+
+---- short BS  -> *
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode SBS.ShortByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BS.ByteString where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BS.L.ByteString where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BB.Builder where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode SBS.ShortByteString T.L.Text where
+  encode = T.L.fromStrict . T.decodeLatin1 . encode
+
+instance Encode SBS.ShortByteString TB.Builder where
+  encode = TB.fromText . encode
+#endif
+
+---- BB  -> *
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BB.Builder SBS.ShortByteString where
+  encode = encode . BB.toLazyByteString
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BB.Builder BB.Builder where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder BS.ByteString where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder BS.L.ByteString where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BB.Builder T.L.Text where
+  encode = T.L.decodeLatin1 . encode
+
+instance Encode BB.Builder TB.Builder where
+  encode = TB.fromLazyText . encode
+#endif
+
+------------------------------------------------------------------------------
+
+-- PRIMITIVE
+instance Decode BS.ByteString BS.ByteString where
+  decode = decodeBs2Bs
+
+instance Decode BS.ByteString BS.L.ByteString where
+  decode = fmap bsFromStrict . decode
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BS.ByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BS.ByteString BB.Builder where
+  decode = fmap BB.byteString . decode
+#endif
+
+----
+
+-- PRIMITIVE
+instance Decode BS.L.ByteString BS.L.ByteString where
+  decode = decodeBsL2BsL
+
+instance Decode BS.L.ByteString BS.ByteString where
+  decode = fmap bsToStrict . decode
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BS.L.ByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BS.L.ByteString BB.Builder where
+  decode = fmap BB.byteString . decode
+#endif
+
+----
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode SBS.ShortByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BS.ByteString where
+  decode = decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BS.L.ByteString where
+  decode = decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BB.Builder where
+  decode = decode . SBS.fromShort
+#endif
+
+----
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BB.Builder SBS.ShortByteString where
+  decode = decode . BB.toLazyByteString
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BB.Builder BS.L.ByteString where
+  decode = decode . BB.toLazyByteString
+
+instance Decode BB.Builder BS.ByteString where
+  decode = decode . BB.toLazyByteString
+
+instance Decode BB.Builder BB.Builder where
+  decode = decode . BB.toLazyByteString
+#endif
+
+----
+
+instance Decode T.Text BS.ByteString where
+  decode = decode . T.encodeUtf8
+
+instance Decode T.Text BS.L.ByteString where
+  decode = decode . T.encodeUtf8
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode T.Text SBS.ShortByteString where
+  decode = decode . T.encodeUtf8
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode T.Text BB.Builder where
+  decode = decode . T.encodeUtf8
+#endif
+
+----
+
+instance Decode T.L.Text BS.ByteString where
+  decode = decode . T.L.encodeUtf8
+
+instance Decode T.L.Text BS.L.ByteString where
+  decode = decode . T.L.encodeUtf8
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode T.L.Text SBS.ShortByteString where
+  decode = decode . T.L.encodeUtf8
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode T.L.Text BB.Builder where
+  decode = decode . T.L.encodeUtf8
+#endif
+
+----
+
+instance Decode TB.Builder BS.ByteString where
+  decode = decode . TB.toLazyText
+
+instance Decode TB.Builder BS.L.ByteString where
+  decode = decode . TB.toLazyText
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode TB.Builder SBS.ShortByteString where
+  decode = decode . TB.toLazyText
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode TB.Builder BB.Builder where
+  decode = decode . TB.toLazyText
+#endif
diff --git a/src/Codec/Base64.hs b/src/Codec/Base64.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Base64.hs
@@ -0,0 +1,317 @@
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+-- | This module provides access to the \"base64\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).
+--
+-- This module is intended to be imported @qualified@, e.g.
+--
+-- > import qualified Codec.Base64 as B64
+--
+-- If you want to explictly specify which 'Encode' and 'Decode' typeclass instance is used, you can use plain Haskell2010 type-signature annotations, e.g.
+--
+-- >>> (B64.encode :: ByteString -> Text) "\x00\x00"
+-- "AAA="
+--
+-- >>> (B64.decode :: Text -> Either String ShortByteString) "NDoyMA=="
+-- Right "4:20"
+--
+-- Alternatively, starting with GHC 8.0.1, you can also use the [TypeApplications language extension](https://downloads.haskell.org/~ghc/8.4.1/docs/html/users_guide/glasgow_exts.html#ghc-flag--XTypeApplications):
+--
+-- >>> B64.encode @ShortByteString @Text "\xFF\239"
+-- "/+8="
+--
+-- >>> B64.decode @Text @ShortByteString "/+8="
+-- Right "\255\239"
+--
+-- @since 0.1.0.0
+module Codec.Base64
+    ( Encode(encode)
+    , Decode(decode)
+    ) where
+
+import qualified Data.ByteString.Base64       as B64
+import qualified Data.ByteString.Base64.Lazy  as B64.L
+
+import qualified Data.ByteString              as BS
+#if MIN_VERSION_bytestring(0,10,2)
+import qualified Data.ByteString.Builder      as BB
+#elif MIN_VERSION_bytestring(0,10,0)
+import qualified Data.ByteString.Lazy.Builder as BB
+#endif
+import qualified Data.ByteString.Lazy         as BS.L
+#if MIN_VERSION_bytestring(0,10,4)
+import qualified Data.ByteString.Short        as SBS
+#endif
+
+import qualified Data.Text                    as T (Text)
+import qualified Data.Text.Encoding           as T (decodeLatin1, encodeUtf8)
+import qualified Data.Text.Lazy               as T.L (Text, fromStrict)
+import qualified Data.Text.Lazy.Builder       as TB (Builder, fromLazyText,
+                                                     fromText, toLazyText)
+import qualified Data.Text.Lazy.Encoding      as T.L (decodeLatin1, encodeUtf8)
+
+import           Internal
+
+-- primitives
+
+decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString
+decodeBs2Bs = B64.decode
+
+decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString
+decodeBsL2BsL = B64.L.decode
+
+encodeBs2Bs :: BS.ByteString -> BS.ByteString
+encodeBs2Bs = B64.encode
+
+encodeBsL2BsL :: BS.L.ByteString -> BS.L.ByteString
+encodeBsL2BsL = B64.L.encode
+
+----------------------------------------------------------------------------
+-- exposed API
+
+-- | Typeclass representing types for which a binary-to-text @base64@ encoding is defined
+class Encode bin txt where
+  -- | Encode binary data using @base64@ text encoding
+  encode :: bin -> txt
+
+-- | Typeclass representing types for which a text-to-binary @base64@ decoding is defined
+class Decode txt bin where
+  -- | Decode binary data encoded textually as @base64@
+  decode :: txt -> Either String bin
+
+----------------------------------------------------------------------------
+-- instance matrix
+
+---- lazy BS -> *
+
+-- PRIMITIVE
+instance Encode BS.L.ByteString BS.L.ByteString where
+  encode = encodeBsL2BsL
+
+instance Encode BS.L.ByteString BS.ByteString where
+  encode = bsToStrict . encode
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BS.L.ByteString BB.Builder where
+  encode = BB.lazyByteString . encode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BS.L.ByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode
+#endif
+
+instance Encode BS.L.ByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BS.L.ByteString T.L.Text where
+  encode = T.L.decodeLatin1 . encode
+
+instance Encode BS.L.ByteString TB.Builder where
+  encode = TB.fromLazyText . encode
+
+---- strict BS  -> *
+
+-- PRIMITIVE
+instance Encode BS.ByteString BS.ByteString where
+  encode = encodeBs2Bs
+
+instance Encode BS.ByteString BS.L.ByteString where
+  encode = bsFromStrict . encode
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BS.ByteString BB.Builder where
+  encode = BB.byteString . encode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BS.ByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode
+#endif
+
+instance Encode BS.ByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BS.ByteString T.L.Text where
+  encode = T.L.fromStrict . T.decodeLatin1 . encode
+
+instance Encode BS.ByteString TB.Builder where
+  encode = TB.fromText . encode
+
+---- short BS  -> *
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode SBS.ShortByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BS.ByteString where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BS.L.ByteString where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BB.Builder where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode SBS.ShortByteString T.L.Text where
+  encode = T.L.fromStrict . T.decodeLatin1 . encode
+
+instance Encode SBS.ShortByteString TB.Builder where
+  encode = TB.fromText . encode
+#endif
+
+---- BB  -> *
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BB.Builder SBS.ShortByteString where
+  encode = encode . BB.toLazyByteString
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BB.Builder BB.Builder where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder BS.ByteString where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder BS.L.ByteString where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BB.Builder T.L.Text where
+  encode = T.L.decodeLatin1 . encode
+
+instance Encode BB.Builder TB.Builder where
+  encode = TB.fromLazyText . encode
+#endif
+
+------------------------------------------------------------------------------
+
+-- PRIMITIVE
+instance Decode BS.ByteString BS.ByteString where
+  decode = decodeBs2Bs
+
+instance Decode BS.ByteString BS.L.ByteString where
+  decode = fmap bsFromStrict . decode
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BS.ByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BS.ByteString BB.Builder where
+  decode = fmap BB.byteString . decode
+#endif
+
+----
+
+-- PRIMITIVE
+instance Decode BS.L.ByteString BS.L.ByteString where
+  decode = decodeBsL2BsL
+
+instance Decode BS.L.ByteString BS.ByteString where
+  decode = fmap bsToStrict . decode
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BS.L.ByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BS.L.ByteString BB.Builder where
+  decode = fmap BB.byteString . decode
+#endif
+
+----
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode SBS.ShortByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BS.ByteString where
+  decode = decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BS.L.ByteString where
+  decode = decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BB.Builder where
+  decode = decode . SBS.fromShort
+#endif
+
+----
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BB.Builder SBS.ShortByteString where
+  decode = decode . BB.toLazyByteString
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BB.Builder BS.L.ByteString where
+  decode = decode . BB.toLazyByteString
+
+instance Decode BB.Builder BS.ByteString where
+  decode = decode . BB.toLazyByteString
+
+instance Decode BB.Builder BB.Builder where
+  decode = decode . BB.toLazyByteString
+#endif
+
+----
+
+instance Decode T.Text BS.ByteString where
+  decode = decode . T.encodeUtf8
+
+instance Decode T.Text BS.L.ByteString where
+  decode = decode . T.encodeUtf8
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode T.Text SBS.ShortByteString where
+  decode = decode . T.encodeUtf8
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode T.Text BB.Builder where
+  decode = decode . T.encodeUtf8
+#endif
+
+----
+
+instance Decode T.L.Text BS.ByteString where
+  decode = decode . T.L.encodeUtf8
+
+instance Decode T.L.Text BS.L.ByteString where
+  decode = decode . T.L.encodeUtf8
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode T.L.Text SBS.ShortByteString where
+  decode = decode . T.L.encodeUtf8
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode T.L.Text BB.Builder where
+  decode = decode . T.L.encodeUtf8
+#endif
+
+----
+
+instance Decode TB.Builder BS.ByteString where
+  decode = decode . TB.toLazyText
+
+instance Decode TB.Builder BS.L.ByteString where
+  decode = decode . TB.toLazyText
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode TB.Builder SBS.ShortByteString where
+  decode = decode . TB.toLazyText
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode TB.Builder BB.Builder where
+  decode = decode . TB.toLazyText
+#endif
diff --git a/src/Codec/Base64Url.hs b/src/Codec/Base64Url.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Base64Url.hs
@@ -0,0 +1,318 @@
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+-- | This module provides access to the \"base64url\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).
+--
+-- This module is intended to be imported @qualified@, e.g.
+--
+-- > import qualified Codec.Base64Url as B64
+--
+-- If you want to explictly specify which 'Encode' and 'Decode' typeclass instance is used, you can use plain Haskell2010 type-signature annotations, e.g.
+--
+-- >>> (B64.encode :: ByteString -> Text) "\x00\x00"
+-- "AAA="
+--
+-- >>> (B64.decode :: Text -> Either String ShortByteString) "NDoyMA=="
+-- Right "4:20"
+--
+-- Alternatively, starting with GHC 8.0.1, you can also use the [TypeApplications language extension](https://downloads.haskell.org/~ghc/8.4.1/docs/html/users_guide/glasgow_exts.html#ghc-flag--XTypeApplications):
+--
+-- >>> B64.encode @ShortByteString @Text "\xFF\239"
+-- "_-8="
+--
+-- >>> B64.decode @Text @ShortByteString "_-8="
+-- Right "\255\239"
+--
+-- @since 0.1.0.0
+module Codec.Base64Url
+    ( Encode(encode)
+    , Decode(decode)
+    ) where
+
+import qualified Data.ByteString.Base64.URL      as B64
+import qualified Data.ByteString.Base64.URL.Lazy as B64.L
+
+import qualified Data.ByteString                 as BS
+#if MIN_VERSION_bytestring(0,10,2)
+import qualified Data.ByteString.Builder         as BB
+#elif MIN_VERSION_bytestring(0,10,0)
+import qualified Data.ByteString.Lazy.Builder    as BB
+#endif
+import qualified Data.ByteString.Lazy            as BS.L
+#if MIN_VERSION_bytestring(0,10,4)
+import qualified Data.ByteString.Short           as SBS
+#endif
+
+import qualified Data.Text                       as T (Text)
+import qualified Data.Text.Encoding              as T (decodeLatin1, encodeUtf8)
+import qualified Data.Text.Lazy                  as T.L (Text, fromStrict)
+import qualified Data.Text.Lazy.Builder          as TB (Builder, fromLazyText,
+                                                        fromText, toLazyText)
+import qualified Data.Text.Lazy.Encoding         as T.L (decodeLatin1,
+                                                         encodeUtf8)
+
+import           Internal
+
+-- primitives
+
+decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString
+decodeBs2Bs = B64.decode
+
+decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString
+decodeBsL2BsL = B64.L.decode
+
+encodeBs2Bs :: BS.ByteString -> BS.ByteString
+encodeBs2Bs = B64.encode
+
+encodeBsL2BsL :: BS.L.ByteString -> BS.L.ByteString
+encodeBsL2BsL = B64.L.encode
+
+----------------------------------------------------------------------------
+-- exposed API
+
+-- | Typeclass representing types for which a binary-to-text @base64url@ encoding is defined
+class Encode bin txt where
+  -- | Encode binary data using @base64url@ text encoding
+  encode :: bin -> txt
+
+-- | Typeclass representing types for which a text-to-binary @base64url@ decoding is defined
+class Decode txt bin where
+  -- | Decode binary data encoded textually as @base64url@
+  decode :: txt -> Either String bin
+
+----------------------------------------------------------------------------
+-- instance matrix
+
+---- lazy BS -> *
+
+-- PRIMITIVE
+instance Encode BS.L.ByteString BS.L.ByteString where
+  encode = encodeBsL2BsL
+
+instance Encode BS.L.ByteString BS.ByteString where
+  encode = bsToStrict . encode
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BS.L.ByteString BB.Builder where
+  encode = BB.lazyByteString . encode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BS.L.ByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode
+#endif
+
+instance Encode BS.L.ByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BS.L.ByteString T.L.Text where
+  encode = T.L.decodeLatin1 . encode
+
+instance Encode BS.L.ByteString TB.Builder where
+  encode = TB.fromLazyText . encode
+
+---- strict BS  -> *
+
+-- PRIMITIVE
+instance Encode BS.ByteString BS.ByteString where
+  encode = encodeBs2Bs
+
+instance Encode BS.ByteString BS.L.ByteString where
+  encode = bsFromStrict . encode
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BS.ByteString BB.Builder where
+  encode = BB.byteString . encode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BS.ByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode
+#endif
+
+instance Encode BS.ByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BS.ByteString T.L.Text where
+  encode = T.L.fromStrict . T.decodeLatin1 . encode
+
+instance Encode BS.ByteString TB.Builder where
+  encode = TB.fromText . encode
+
+---- short BS  -> *
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode SBS.ShortByteString SBS.ShortByteString where
+  encode = SBS.toShort . encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BS.ByteString where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BS.L.ByteString where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString BB.Builder where
+  encode = encode . SBS.fromShort
+
+instance Encode SBS.ShortByteString T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode SBS.ShortByteString T.L.Text where
+  encode = T.L.fromStrict . T.decodeLatin1 . encode
+
+instance Encode SBS.ShortByteString TB.Builder where
+  encode = TB.fromText . encode
+#endif
+
+---- BB  -> *
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Encode BB.Builder SBS.ShortByteString where
+  encode = encode . BB.toLazyByteString
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Encode BB.Builder BB.Builder where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder BS.ByteString where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder BS.L.ByteString where
+  encode = encode . BB.toLazyByteString
+
+instance Encode BB.Builder T.Text where
+  encode = T.decodeLatin1 . encode
+
+instance Encode BB.Builder T.L.Text where
+  encode = T.L.decodeLatin1 . encode
+
+instance Encode BB.Builder TB.Builder where
+  encode = TB.fromLazyText . encode
+#endif
+
+------------------------------------------------------------------------------
+
+-- PRIMITIVE
+instance Decode BS.ByteString BS.ByteString where
+  decode = decodeBs2Bs
+
+instance Decode BS.ByteString BS.L.ByteString where
+  decode = fmap bsFromStrict . decode
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BS.ByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BS.ByteString BB.Builder where
+  decode = fmap BB.byteString . decode
+#endif
+
+----
+
+-- PRIMITIVE
+instance Decode BS.L.ByteString BS.L.ByteString where
+  decode = decodeBsL2BsL
+
+instance Decode BS.L.ByteString BS.ByteString where
+  decode = fmap bsToStrict . decode
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BS.L.ByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BS.L.ByteString BB.Builder where
+  decode = fmap BB.byteString . decode
+#endif
+
+----
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode SBS.ShortByteString SBS.ShortByteString where
+  decode = fmap SBS.toShort . decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BS.ByteString where
+  decode = decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BS.L.ByteString where
+  decode = decode . SBS.fromShort
+
+instance Decode SBS.ShortByteString BB.Builder where
+  decode = decode . SBS.fromShort
+#endif
+
+----
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode BB.Builder SBS.ShortByteString where
+  decode = decode . BB.toLazyByteString
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode BB.Builder BS.L.ByteString where
+  decode = decode . BB.toLazyByteString
+
+instance Decode BB.Builder BS.ByteString where
+  decode = decode . BB.toLazyByteString
+
+instance Decode BB.Builder BB.Builder where
+  decode = decode . BB.toLazyByteString
+#endif
+
+----
+
+instance Decode T.Text BS.ByteString where
+  decode = decode . T.encodeUtf8
+
+instance Decode T.Text BS.L.ByteString where
+  decode = decode . T.encodeUtf8
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode T.Text SBS.ShortByteString where
+  decode = decode . T.encodeUtf8
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode T.Text BB.Builder where
+  decode = decode . T.encodeUtf8
+#endif
+
+----
+
+instance Decode T.L.Text BS.ByteString where
+  decode = decode . T.L.encodeUtf8
+
+instance Decode T.L.Text BS.L.ByteString where
+  decode = decode . T.L.encodeUtf8
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode T.L.Text SBS.ShortByteString where
+  decode = decode . T.L.encodeUtf8
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode T.L.Text BB.Builder where
+  decode = decode . T.L.encodeUtf8
+#endif
+
+----
+
+instance Decode TB.Builder BS.ByteString where
+  decode = decode . TB.toLazyText
+
+instance Decode TB.Builder BS.L.ByteString where
+  decode = decode . TB.toLazyText
+
+#if MIN_VERSION_bytestring(0,10,4)
+instance Decode TB.Builder SBS.ShortByteString where
+  decode = decode . TB.toLazyText
+#endif
+
+#if MIN_VERSION_bytestring(0,10,0)
+instance Decode TB.Builder BB.Builder where
+  decode = decode . TB.toLazyText
+#endif
diff --git a/src/Internal.hs b/src/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Internal.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE CPP #-}
+
+module Internal
+    ( bsToStrict
+    , bsFromStrict
+    , (<$>)
+    ) where
+
+#if !MIN_VERSION_base(4,8,0)
+import           Control.Applicative
+#endif
+
+import qualified Data.ByteString      as BS
+import qualified Data.ByteString.Lazy as BS.L
+
+{-# INLINE bsToStrict #-}
+bsToStrict :: BS.L.ByteString -> BS.ByteString
+#if MIN_VERSION_bytestring(0,10,0)
+bsToStrict = BS.L.toStrict
+#else
+bsToStrict = BS.concat . BS.L.toChunks
+#endif
+
+{-# INLINE bsFromStrict #-}
+bsFromStrict :: BS.ByteString -> BS.L.ByteString
+#if MIN_VERSION_bytestring(0,10,0)
+bsFromStrict = BS.L.fromStrict
+#else
+bsFromStrict = BS.L.fromChunks . (:[])
+#endif
