diff --git a/httputil/session.go b/httputil/session.go
deleted file mode 100644
index 5d2872eab361e583b2da660924e4930aa975178d..0000000000000000000000000000000000000000
--- a/httputil/session.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package httputil
-
-import (
-	"encoding/gob"
-	"log"
-	"net/http"
-	"time"
-
-	"github.com/gorilla/sessions"
-)
-
-// ExpiringSession is a session with server-side expiration check.
-// Session data is saved in signed, encrypted cookies in the
-// browser. We'd like these cookies to expire when a certain amount of
-// time passes, or when the user closes the browser. We trust the
-// browser for the latter, but we enforce time-based expiration on the
-// server.
-type ExpiringSession struct {
-	*sessions.Session
-}
-
-// GetExpiringSession wraps a Session (obtained from 'store') with
-// an ExpiringSession. If it's invalid or expired, a new empty Session
-// will be created with an expiration time set using 'ttl'.
-func GetExpiringSession(req *http.Request, store sessions.Store, key string, ttl time.Duration) (*ExpiringSession, error) {
-	now := time.Now()
-
-	// An error here just means that we failed to decode the
-	// existing session for some reason. A new session will always
-	// be returned, so we just pass along the error to the caller
-	// (so it can be logged).
-	s, err := store.Get(req, key)
-
-	// See if we have a valid session first.
-	if !s.IsNew {
-		if exp, ok := s.Values["_exp"].(time.Time); ok && now.Before(exp) {
-			return &ExpiringSession{Session: s}, err
-		}
-		// We can't call sessions.NewSession() because that
-		// won't register the session with the Registry, so it
-		// won't be sent with the response. Wipe the data
-		// instead.
-		for k := range s.Values {
-			delete(s.Values, k)
-		}
-	}
-
-	// The session is either invalid or expired, create a new
-	// blank one containing no data.
-	expiry := now.Add(ttl)
-	s.Values["_exp"] = expiry
-
-	return &ExpiringSession{Session: s}, err
-}
-
-// Wrapper for an http.ResponseWriter that ensures all tracked
-// sessions are saved before the request body is sent.
-//
-// We have to duplicate the logic to call WriteHeader on the first
-// Write, otherwise the underlying ResponseWriter won't call our
-// WriteHeader function but its own instead.
-type sessionResponseWriter struct {
-	http.ResponseWriter
-	headerWritten bool
-	req           *http.Request
-}
-
-func (w *sessionResponseWriter) WriteHeader(statusCode int) {
-	if statusCode >= 200 && statusCode < 400 {
-		if err := sessions.Save(w.req, w.ResponseWriter); err != nil {
-			log.Printf("error saving sessions: %v", err)
-		}
-	}
-	w.ResponseWriter.WriteHeader(statusCode)
-	w.headerWritten = true
-}
-
-func (w *sessionResponseWriter) Write(b []byte) (int, error) {
-	if !w.headerWritten {
-		w.WriteHeader(http.StatusOK)
-	}
-	return w.ResponseWriter.Write(b)
-}
-
-// NewSessionResponseWriter returns a wrapped http.ResponseWriter that
-// will always remember to save the Gorilla sessions before writing
-// the response body.
-func NewSessionResponseWriter(w http.ResponseWriter, req *http.Request) http.ResponseWriter {
-	return &sessionResponseWriter{
-		ResponseWriter: w,
-		req:            req,
-	}
-}
-
-func init() {
-	// Register time.Time with encoding/gob, to ensure that the
-	// ExpiringSession timestamp can be serialized.
-	var t time.Time
-	gob.Register(t)
-}
diff --git a/httputil/session_test.go b/httputil/session_test.go
deleted file mode 100644
index b46817117da6bab86633f1234336161eb813eae6..0000000000000000000000000000000000000000
--- a/httputil/session_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package httputil
-
-import (
-	"encoding/gob"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/gorilla/sessions"
-)
-
-type mySession struct {
-	Data string
-}
-
-func init() {
-	gob.Register(&mySession{})
-}
-
-func TestExpiringSession(t *testing.T) {
-	store := sessions.NewCookieStore()
-	req, _ := http.NewRequest("GET", "http://localhost/", nil)
-
-	httpsess, err := GetExpiringSession(req, store, "testkey", 60*time.Second)
-	if err != nil {
-		t.Errorf("store.Get error: %v", err)
-	}
-
-	if _, ok := httpsess.Values["mykey"].(*mySession); ok {
-		t.Fatal("got a session without any data")
-	}
-}
diff --git a/server/http.go b/server/http.go
index a8227fef28fd0a8c311ee7b908acad18ad741a63..d0ddb50baf40b0ed4bb88fb7e87d9c73a24dba80 100644
--- a/server/http.go
+++ b/server/http.go
@@ -24,8 +24,8 @@ import (
 	authclient "git.autistici.org/id/auth/client"
 	ksclient "git.autistici.org/id/keystore/client"
 
-	"git.autistici.org/id/go-sso/httputil"
 	"git.autistici.org/id/go-sso/server/device"
+	"git.autistici.org/id/go-sso/server/httputil"
 	"git.autistici.org/id/go-sso/server/login"
 )
 
diff --git a/httputil/headers.go b/server/httputil/headers.go
similarity index 100%
rename from httputil/headers.go
rename to server/httputil/headers.go
diff --git a/httputil/renderer.go b/server/httputil/renderer.go
similarity index 100%
rename from httputil/renderer.go
rename to server/httputil/renderer.go
diff --git a/httputil/static.go b/server/httputil/static.go
similarity index 100%
rename from httputil/static.go
rename to server/httputil/static.go
diff --git a/server/login/login.go b/server/login/login.go
index d936618500efb5fed3edef8d8b939ba7b9c6f6dd..c524acc87d4acb470b544e853d7d5f4f3de38b04 100644
--- a/server/login/login.go
+++ b/server/login/login.go
@@ -2,7 +2,6 @@ package login
 
 import (
 	"context"
-	"encoding/gob"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -13,16 +12,13 @@ import (
 
 	"git.autistici.org/id/auth"
 	authclient "git.autistici.org/id/auth/client"
-	"github.com/gorilla/sessions"
 	"github.com/tstranex/u2f"
 	"go.opencensus.io/trace"
 
-	"git.autistici.org/id/go-sso/httputil"
 	"git.autistici.org/id/go-sso/server/device"
+	"git.autistici.org/id/go-sso/server/httputil"
 )
 
-const loginSessionKey = "_auth"
-
 const maxFailures = 5
 
 type Auth struct {
@@ -56,6 +52,9 @@ type loginSession struct {
 	AuthResponse *auth.Response
 	Redir        string
 	Failures     int
+
+	// Implementation detail of the session layer.
+	deleted bool
 }
 
 func (l *loginSession) Reset() {
@@ -90,29 +89,8 @@ func (l *loginSession) Can2FA(method auth.TFAMethod) error {
 	return nil
 }
 
-func init() {
-	gob.Register(&loginSession{})
-}
-
-type loginSessionInt struct {
-	*loginSession
-	httpSession *httputil.ExpiringSession
-}
-
-func (s *loginSessionInt) Delete(req *http.Request, w http.ResponseWriter) {
-	delete(s.httpSession.Values, "data")
-	s.httpSession.Options.MaxAge = -1
-}
-
-func newLoginSession(hs *httputil.ExpiringSession, s *loginSession) *loginSessionInt {
-	if s == nil {
-		s = new(loginSession)
-		hs.Values["data"] = s
-	}
-	return &loginSessionInt{
-		loginSession: s,
-		httpSession:  hs,
-	}
+func (l *loginSession) Delete() {
+	l.deleted = true
 }
 
 type ctxKey int
@@ -138,7 +116,7 @@ type LoginCallback func(context.Context, string, string, *auth.UserInfo) error
 // Login wraps an http.Handler with a login workflow.
 type Login struct {
 	wrap             http.Handler
-	sessionStore     sessions.Store
+	sessionMgr       *sessionManager
 	sessionTTL       time.Duration
 	urlPrefix        string
 	renderer         *httputil.Renderer
@@ -152,21 +130,14 @@ type Login struct {
 
 // New returns a new Login wrapper.
 func New(wrap http.Handler, devMgr *device.Manager, authClient authclient.Client, authService, u2fAppID, urlPrefix, fallbackRedirect string, renderer *httputil.Renderer, callback LoginCallback, keyPairs [][]byte, sessionTTL time.Duration) *Login {
-	store := sessions.NewCookieStore(keyPairs...)
-	store.Options = &sessions.Options{
-		HttpOnly: true,
-		Secure:   true,
-		MaxAge:   0,
-		Path:     urlPrefix + "/",
-	}
-
 	if sessionTTL == 0 {
 		sessionTTL = 20 * time.Hour // default TTL.
 	}
+	smgr := newSessionManager(urlPrefix+"/", keyPairs[0], keyPairs[1], sessionTTL)
 
 	return &Login{
 		wrap:             wrap,
-		sessionStore:     store,
+		sessionMgr:       smgr,
 		sessionTTL:       sessionTTL,
 		urlPrefix:        urlPrefix,
 		renderer:         renderer,
@@ -183,58 +154,51 @@ func (l *Login) urlFor(path string) string {
 	return l.urlPrefix + path
 }
 
-func (l *Login) fetchOrInitSession(req *http.Request) *loginSessionInt {
-	httpSession, err := httputil.GetExpiringSession(req, l.sessionStore, loginSessionKey, l.sessionTTL)
+func (l *Login) fetchOrInitSession(req *http.Request) *loginSession {
+	session, err := l.sessionMgr.getSession(req)
 	if err != nil {
-		log.Printf("sessionStore.Get error: %v", err)
-	}
-	var session *loginSessionInt
-	if inner, ok := httpSession.Values["data"].(*loginSession); ok {
-		session = newLoginSession(httpSession, inner)
-	} else {
-		// Initialize a new session.
-		session = newLoginSession(httpSession, nil)
+		return new(loginSession)
 	}
 	return session
 }
 
 func (l *Login) ServeHTTP(w http.ResponseWriter, req *http.Request) {
-	sess := l.fetchOrInitSession(req)
+	session := l.fetchOrInitSession(req)
 
-	// This way we don't have to call sess.Save explicitly.
-	w = httputil.NewSessionResponseWriter(w, req)
+	// Ensure that the session is saved.
+	w = l.sessionMgr.newSessionResponseWriter(w, req, session)
 
 	// A very simple router.
 	switch req.URL.Path {
 	case l.urlFor("/login"):
-		l.handleLogin(w, req, sess)
+		l.handleLogin(w, req, session)
 	case l.urlFor("/login/u2f"):
-		l.handleLoginU2F(w, req, sess)
+		l.handleLoginU2F(w, req, session)
 	case l.urlFor("/login/otp"):
-		l.handleLoginOTP(w, req, sess)
+		l.handleLoginOTP(w, req, session)
 	default:
 		// Wipe the session on logout, before passing through to the
 		// wrapped handler. Note that the Auth object will still
 		// contain valid data, but Authenticated will be set to false.
 		if req.URL.Path == l.urlFor("/logout") {
-			log.Printf("logging out user %s", sess.Username)
-			sess.Authenticated = false
-			sess.Delete(req, w)
-		} else if !sess.Authenticated {
+			log.Printf("logging out user %s", session.Username)
+			session.Authenticated = false
+			session.Delete()
+		} else if !session.Authenticated {
 			// Save the current URL in the session for later redirect.
-			sess.Redir = req.URL.String()
+			session.Redir = req.URL.String()
 			http.Redirect(w, req, "/login", http.StatusFound)
 			return
 		}
 
 		// Pass the AuthContext to the wrapped Handler via the
 		// request context.
-		req = req.WithContext(withAuth(req.Context(), &sess.Auth))
+		req = req.WithContext(withAuth(req.Context(), &session.Auth))
 		l.wrap.ServeHTTP(w, req)
 	}
 }
 
-func (l *Login) loginOk(w http.ResponseWriter, req *http.Request, sess *loginSessionInt, password string) {
+func (l *Login) loginOk(w http.ResponseWriter, req *http.Request, sess *loginSession, password string) {
 	if l.callback != nil {
 		if err := l.callback(req.Context(), sess.Username, password, sess.UserInfo); err != nil {
 			log.Printf("login callback error: %v", err)
@@ -258,7 +222,7 @@ func (l *Login) loginOk(w http.ResponseWriter, req *http.Request, sess *loginSes
 	http.Redirect(w, req, target, http.StatusFound)
 }
 
-func (l *Login) handleLogin(w http.ResponseWriter, req *http.Request, sess *loginSessionInt) {
+func (l *Login) handleLogin(w http.ResponseWriter, req *http.Request, sess *loginSession) {
 	if req.Method != "GET" && req.Method != "POST" {
 		http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
 		return
@@ -311,7 +275,7 @@ func (l *Login) handleLogin(w http.ResponseWriter, req *http.Request, sess *logi
 	l.renderer.Render(w, req, "login_password.html", env)
 }
 
-func (l *Login) handleLoginOTP(w http.ResponseWriter, req *http.Request, sess *loginSessionInt) {
+func (l *Login) handleLoginOTP(w http.ResponseWriter, req *http.Request, sess *loginSession) {
 	if req.Method != "GET" && req.Method != "POST" {
 		http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
 		return
@@ -353,7 +317,7 @@ func (l *Login) handleLoginOTP(w http.ResponseWriter, req *http.Request, sess *l
 	l.renderer.Render(w, req, "login_otp.html", env)
 }
 
-func (l *Login) handleLoginU2F(w http.ResponseWriter, req *http.Request, sess *loginSessionInt) {
+func (l *Login) handleLoginU2F(w http.ResponseWriter, req *http.Request, sess *loginSession) {
 	if req.Method != "GET" && req.Method != "POST" {
 		http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
 		return
diff --git a/server/login/session.go b/server/login/session.go
new file mode 100644
index 0000000000000000000000000000000000000000..fbaf8b80352dab68f561ea93f6d2b90b6642306b
--- /dev/null
+++ b/server/login/session.go
@@ -0,0 +1,109 @@
+package login
+
+import (
+	"encoding/gob"
+	"log"
+	"net/http"
+	"time"
+
+	"github.com/gorilla/securecookie"
+)
+
+func init() {
+	gob.Register(&loginSession{})
+}
+
+const sessionCookieName = "_sso_auth"
+
+type sessionManager struct {
+	sc   *securecookie.SecureCookie
+	path string
+}
+
+func newSessionManager(path string, authKey, encKey []byte, ttl time.Duration) *sessionManager {
+	sc := securecookie.New(authKey, encKey)
+	sc.MaxAge(int(ttl.Seconds()))
+	// The JSON encoder generates smaller data than gob in our case.
+	sc.SetSerializer(&securecookie.JSONEncoder{})
+	return &sessionManager{
+		sc:   sc,
+		path: path,
+	}
+}
+
+func (m *sessionManager) getSession(req *http.Request) (*loginSession, error) {
+	cookie, err := req.Cookie(sessionCookieName)
+	if err != nil {
+		return nil, err
+	}
+	var s loginSession
+	err = m.sc.Decode(sessionCookieName, cookie.Value, &s)
+	if err != nil {
+		return nil, err
+	}
+	return &s, nil
+}
+
+func (m *sessionManager) setSession(w http.ResponseWriter, session *loginSession) (err error) {
+	var encoded string
+	if !session.deleted {
+		encoded, err = m.sc.Encode(sessionCookieName, session)
+		if err != nil {
+			return
+		}
+	}
+	cookie := &http.Cookie{
+		Name:     sessionCookieName,
+		Value:    encoded,
+		Path:     m.path,
+		Secure:   true,
+		HttpOnly: true,
+	}
+	if session.deleted {
+		cookie.MaxAge = -1
+	}
+	http.SetCookie(w, cookie)
+	return
+}
+
+// Wrapper for an http.ResponseWriter that ensures all tracked
+// sessions are saved before the request body is sent.
+//
+// We have to duplicate the logic to call WriteHeader on the first
+// Write, otherwise the underlying ResponseWriter won't call our
+// WriteHeader function but its own instead.
+type sessionResponseWriter struct {
+	http.ResponseWriter
+	headerWritten bool
+	req           *http.Request
+	mgr           *sessionManager
+	session       *loginSession
+}
+
+func (w *sessionResponseWriter) WriteHeader(statusCode int) {
+	if statusCode >= 200 && statusCode < 400 {
+		if err := w.mgr.setSession(w, w.session); err != nil {
+			log.Printf("error saving sessions: %v", err)
+		}
+	}
+	w.ResponseWriter.WriteHeader(statusCode)
+	w.headerWritten = true
+}
+
+func (w *sessionResponseWriter) Write(b []byte) (int, error) {
+	if !w.headerWritten {
+		w.WriteHeader(http.StatusOK)
+	}
+	return w.ResponseWriter.Write(b)
+}
+
+// newSessionResponseWriter returns a wrapped http.ResponseWriter that
+// will always save the session before writing the response body.
+func (m *sessionManager) newSessionResponseWriter(w http.ResponseWriter, req *http.Request, session *loginSession) http.ResponseWriter {
+	return &sessionResponseWriter{
+		ResponseWriter: w,
+		req:            req,
+		mgr:            m,
+		session:        session,
+	}
+}
diff --git a/vendor/github.com/gorilla/sessions/AUTHORS b/vendor/github.com/gorilla/sessions/AUTHORS
deleted file mode 100644
index 1e3e7acb629636728fb6f6f23bc6e5d16497db2a..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/AUTHORS
+++ /dev/null
@@ -1,43 +0,0 @@
-# This is the official list of gorilla/sessions authors for copyright purposes.
-#
-# Please keep the list sorted.
-
-Ahmadreza Zibaei <ahmadrezazibaei@hotmail.com>
-Anton Lindström <lindztr@gmail.com>
-Brian Jones <mojobojo@gmail.com>
-Collin Stedman <kronion@users.noreply.github.com>
-Deniz Eren <dee.116@gmail.com>
-Dmitry Chestnykh <dmitry@codingrobots.com>
-Dustin Oprea <myselfasunder@gmail.com>
-Egon Elbre <egonelbre@gmail.com>
-enumappstore <appstore@enumapps.com>
-Geofrey Ernest <geofreyernest@live.com>
-Google LLC (https://opensource.google.com/)
-Jerry Saravia <SaraviaJ@gmail.com>
-Jonathan Gillham <jonathan.gillham@gamil.com>
-Justin Clift <justin@postgresql.org>
-Justin Hellings <justin.hellings@gmail.com>
-Kamil Kisiel <kamil@kamilkisiel.net>
-Keiji Yoshida <yoshida.keiji.84@gmail.com>
-kliron <kliron@gmail.com>
-Kshitij Saraogi <KshitijSaraogi@gmail.com>
-Lauris BH <lauris@nix.lv>
-Lukas Rist <glaslos@gmail.com>
-Mark Dain <ancarda@users.noreply.github.com>
-Matt Ho <matt.ho@gmail.com>
-Matt Silverlock <matt@eatsleeprepeat.net>
-Mattias Wadman <mattias.wadman@gmail.com>
-Michael Schuett <michaeljs1990@gmail.com>
-Michael Stapelberg <stapelberg@users.noreply.github.com>
-Mirco Zeiss <mirco.zeiss@gmail.com>
-moraes <rodrigo.moraes@gmail.com>
-nvcnvn <nguyen@open-vn.org>
-pappz <zoltan.pmail@gmail.com>
-Pontus Leitzler <leitzler@users.noreply.github.com>
-QuaSoft <info@quasoft.net>
-rcadena <robert.cadena@gmail.com>
-rodrigo moraes <rodrigo.moraes@gmail.com>
-Shawn Smith <shawnpsmith@gmail.com>
-Taylor Hurt <taylor.a.hurt@gmail.com>
-Tortuoise <sanyasinp@gmail.com>
-Vitor De Mario <vitordemario@gmail.com>
diff --git a/vendor/github.com/gorilla/sessions/LICENSE b/vendor/github.com/gorilla/sessions/LICENSE
deleted file mode 100644
index 6903df6386e98928a3236b87c84b71260c2541a6..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2012-2018 The Gorilla Authors. 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 Google Inc. nor the names of its
-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/vendor/github.com/gorilla/sessions/README.md b/vendor/github.com/gorilla/sessions/README.md
deleted file mode 100644
index d4d70e9d1cd7231a000fdf8893ef5930b2929889..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/README.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# sessions
-
-[![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.svg?branch=master)](https://travis-ci.org/gorilla/sessions)
-[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/sessions/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/sessions?badge)
-
-gorilla/sessions provides cookie and filesystem sessions and infrastructure for
-custom session backends.
-
-The key features are:
-
-- Simple API: use it as an easy way to set signed (and optionally
-  encrypted) cookies.
-- Built-in backends to store sessions in cookies or the filesystem.
-- Flash messages: session values that last until read.
-- Convenient way to switch session persistency (aka "remember me") and set
-  other attributes.
-- Mechanism to rotate authentication and encryption keys.
-- Multiple sessions per request, even using different backends.
-- Interfaces and infrastructure for custom session backends: sessions from
-  different stores can be retrieved and batch-saved using a common API.
-
-Let's start with an example that shows the sessions API in a nutshell:
-
-```go
-	import (
-		"net/http"
-		"github.com/gorilla/sessions"
-	)
-
-	// Note: Don't store your key in your source code. Pass it via an
-	// environmental variable, or flag (or both), and don't accidentally commit it
-	// alongside your code. Ensure your key is sufficiently random - i.e. use Go's
-	// crypto/rand or securecookie.GenerateRandomKey(32) and persist the result.
-	var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session. We're ignoring the error resulted from decoding an
-		// existing session: Get() always returns a session, even if empty.
-		session, _ := store.Get(r, "session-name")
-		// Set some session values.
-		session.Values["foo"] = "bar"
-		session.Values[42] = 43
-		// Save it before we write to the response/return from the handler.
-		err = session.Save(r, w)
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-	}
-```
-
-First we initialize a session store calling `NewCookieStore()` and passing a
-secret key used to authenticate the session. Inside the handler, we call
-`store.Get()` to retrieve an existing session or create a new one. Then we set
-some session values in session.Values, which is a `map[interface{}]interface{}`.
-And finally we call `session.Save()` to save the session in the response.
-
-More examples are available [on the Gorilla
-website](https://www.gorillatoolkit.org/pkg/sessions).
-
-## Store Implementations
-
-Other implementations of the `sessions.Store` interface:
-
-- [github.com/starJammer/gorilla-sessions-arangodb](https://github.com/starJammer/gorilla-sessions-arangodb) - ArangoDB
-- [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt
-- [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase
-- [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS
-- [github.com/savaki/dynastore](https://github.com/savaki/dynastore) - DynamoDB on AWS (Official AWS library)
-- [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache
-- [github.com/dsoprea/go-appengine-sessioncascade](https://github.com/dsoprea/go-appengine-sessioncascade) - Memcache/Datastore/Context in AppEngine
-- [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB
-- [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL
-- [github.com/EnumApps/clustersqlstore](https://github.com/EnumApps/clustersqlstore) - MySQL Cluster
-- [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL
-- [github.com/boj/redistore](https://github.com/boj/redistore) - Redis
-- [github.com/rbcervilla/redisstore](https://github.com/rbcervilla/redisstore) - Redis (Single, Sentinel, Cluster)
-- [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB
-- [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak
-- [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite
-- [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite)
-- [github.com/gernest/qlstore](https://github.com/gernest/qlstore) - ql
-- [github.com/quasoft/memstore](https://github.com/quasoft/memstore) - In-memory implementation for use in unit tests
-- [github.com/lafriks/xormstore](https://github.com/lafriks/xormstore) - XORM (MySQL, PostgreSQL, SQLite, Microsoft SQL Server, TiDB)
-- [github.com/GoogleCloudPlatform/firestore-gorilla-sessions](https://github.com/GoogleCloudPlatform/firestore-gorilla-sessions) - Cloud Firestore
-
-## License
-
-BSD licensed. See the LICENSE file for details.
diff --git a/vendor/github.com/gorilla/sessions/cookie.go b/vendor/github.com/gorilla/sessions/cookie.go
deleted file mode 100644
index 1928b0471d9d259e6f18acf0ce96a8a42d78d306..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/cookie.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// +build !go1.11
-
-package sessions
-
-import "net/http"
-
-// newCookieFromOptions returns an http.Cookie with the options set.
-func newCookieFromOptions(name, value string, options *Options) *http.Cookie {
-	return &http.Cookie{
-		Name:     name,
-		Value:    value,
-		Path:     options.Path,
-		Domain:   options.Domain,
-		MaxAge:   options.MaxAge,
-		Secure:   options.Secure,
-		HttpOnly: options.HttpOnly,
-	}
-
-}
diff --git a/vendor/github.com/gorilla/sessions/cookie_go111.go b/vendor/github.com/gorilla/sessions/cookie_go111.go
deleted file mode 100644
index 173d1a3ed12bb983164d7f3705ec927885a06e83..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/cookie_go111.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// +build go1.11
-
-package sessions
-
-import "net/http"
-
-// newCookieFromOptions returns an http.Cookie with the options set.
-func newCookieFromOptions(name, value string, options *Options) *http.Cookie {
-	return &http.Cookie{
-		Name:     name,
-		Value:    value,
-		Path:     options.Path,
-		Domain:   options.Domain,
-		MaxAge:   options.MaxAge,
-		Secure:   options.Secure,
-		HttpOnly: options.HttpOnly,
-		SameSite: options.SameSite,
-	}
-
-}
diff --git a/vendor/github.com/gorilla/sessions/doc.go b/vendor/github.com/gorilla/sessions/doc.go
deleted file mode 100644
index f4673cccf559e6c34a4b13ae6eb0fe16737c7c41..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/doc.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package sessions provides cookie and filesystem sessions and
-infrastructure for custom session backends.
-
-The key features are:
-
-	* Simple API: use it as an easy way to set signed (and optionally
-	  encrypted) cookies.
-	* Built-in backends to store sessions in cookies or the filesystem.
-	* Flash messages: session values that last until read.
-	* Convenient way to switch session persistency (aka "remember me") and set
-	  other attributes.
-	* Mechanism to rotate authentication and encryption keys.
-	* Multiple sessions per request, even using different backends.
-	* Interfaces and infrastructure for custom session backends: sessions from
-	  different stores can be retrieved and batch-saved using a common API.
-
-Let's start with an example that shows the sessions API in a nutshell:
-
-	import (
-		"net/http"
-		"github.com/gorilla/sessions"
-	)
-
-	// Note: Don't store your key in your source code. Pass it via an
-	// environmental variable, or flag (or both), and don't accidentally commit it
-	// alongside your code. Ensure your key is sufficiently random - i.e. use Go's
-	// crypto/rand or securecookie.GenerateRandomKey(32) and persist the result.
-	// Ensure SESSION_KEY exists in the environment, or sessions will fail.
-	var store = sessions.NewCookieStore(os.Getenv("SESSION_KEY"))
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session. Get() always returns a session, even if empty.
-		session, err := store.Get(r, "session-name")
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-
-		// Set some session values.
-		session.Values["foo"] = "bar"
-		session.Values[42] = 43
-		// Save it before we write to the response/return from the handler.
-		err = session.Save(r, w)
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-	}
-
-First we initialize a session store calling NewCookieStore() and passing a
-secret key used to authenticate the session. Inside the handler, we call
-store.Get() to retrieve an existing session or a new one. Then we set some
-session values in session.Values, which is a map[interface{}]interface{}.
-And finally we call session.Save() to save the session in the response.
-
-Note that in production code, we should check for errors when calling
-session.Save(r, w), and either display an error message or otherwise handle it.
-
-Save must be called before writing to the response, otherwise the session
-cookie will not be sent to the client.
-
-That's all you need to know for the basic usage. Let's take a look at other
-options, starting with flash messages.
-
-Flash messages are session values that last until read. The term appeared with
-Ruby On Rails a few years back. When we request a flash message, it is removed
-from the session. To add a flash, call session.AddFlash(), and to get all
-flashes, call session.Flashes(). Here is an example:
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session.
-		session, err := store.Get(r, "session-name")
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-
-		// Get the previous flashes, if any.
-		if flashes := session.Flashes(); len(flashes) > 0 {
-			// Use the flash values.
-		} else {
-			// Set a new flash.
-			session.AddFlash("Hello, flash messages world!")
-		}
-		err = session.Save(r, w)
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-	}
-
-Flash messages are useful to set information to be read after a redirection,
-like after form submissions.
-
-There may also be cases where you want to store a complex datatype within a
-session, such as a struct. Sessions are serialised using the encoding/gob package,
-so it is easy to register new datatypes for storage in sessions:
-
-	import(
-		"encoding/gob"
-		"github.com/gorilla/sessions"
-	)
-
-	type Person struct {
-		FirstName	string
-		LastName 	string
-		Email		string
-		Age			int
-	}
-
-	type M map[string]interface{}
-
-	func init() {
-
-		gob.Register(&Person{})
-		gob.Register(&M{})
-	}
-
-As it's not possible to pass a raw type as a parameter to a function, gob.Register()
-relies on us passing it a value of the desired type. In the example above we've passed
-it a pointer to a struct and a pointer to a custom type representing a
-map[string]interface. (We could have passed non-pointer values if we wished.) This will
-then allow us to serialise/deserialise values of those types to and from our sessions.
-
-Note that because session values are stored in a map[string]interface{}, there's
-a need to type-assert data when retrieving it. We'll use the Person struct we registered above:
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		session, err := store.Get(r, "session-name")
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-
-		// Retrieve our struct and type-assert it
-		val := session.Values["person"]
-		var person = &Person{}
-		if person, ok := val.(*Person); !ok {
-			// Handle the case that it's not an expected type
-		}
-
-		// Now we can use our person object
-	}
-
-By default, session cookies last for a month. This is probably too long for
-some cases, but it is easy to change this and other attributes during
-runtime. Sessions can be configured individually or the store can be
-configured and then all sessions saved using it will use that configuration.
-We access session.Options or store.Options to set a new configuration. The
-fields are basically a subset of http.Cookie fields. Let's change the
-maximum age of a session to one week:
-
-	session.Options = &sessions.Options{
-		Path:     "/",
-		MaxAge:   86400 * 7,
-		HttpOnly: true,
-	}
-
-Sometimes we may want to change authentication and/or encryption keys without
-breaking existing sessions. The CookieStore supports key rotation, and to use
-it you just need to set multiple authentication and encryption keys, in pairs,
-to be tested in order:
-
-	var store = sessions.NewCookieStore(
-		[]byte("new-authentication-key"),
-		[]byte("new-encryption-key"),
-		[]byte("old-authentication-key"),
-		[]byte("old-encryption-key"),
-	)
-
-New sessions will be saved using the first pair. Old sessions can still be
-read because the first pair will fail, and the second will be tested. This
-makes it easy to "rotate" secret keys and still be able to validate existing
-sessions. Note: for all pairs the encryption key is optional; set it to nil
-or omit it and and encryption won't be used.
-
-Multiple sessions can be used in the same request, even with different
-session backends. When this happens, calling Save() on each session
-individually would be cumbersome, so we have a way to save all sessions
-at once: it's sessions.Save(). Here's an example:
-
-	var store = sessions.NewCookieStore([]byte("something-very-secret"))
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session and set a value.
-		session1, _ := store.Get(r, "session-one")
-		session1.Values["foo"] = "bar"
-		// Get another session and set another value.
-		session2, _ := store.Get(r, "session-two")
-		session2.Values[42] = 43
-		// Save all sessions.
-		err = sessions.Save(r, w)
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-	}
-
-This is possible because when we call Get() from a session store, it adds the
-session to a common registry. Save() uses it to save all registered sessions.
-*/
-package sessions
diff --git a/vendor/github.com/gorilla/sessions/go.mod b/vendor/github.com/gorilla/sessions/go.mod
deleted file mode 100644
index 9028bcf1c85e2483484fa781374774da85eeecc8..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/gorilla/sessions
-
-require github.com/gorilla/securecookie v1.1.1
diff --git a/vendor/github.com/gorilla/sessions/go.sum b/vendor/github.com/gorilla/sessions/go.sum
deleted file mode 100644
index e6a7ed5f359b1341228321bd21eceea74152697d..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
-github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
diff --git a/vendor/github.com/gorilla/sessions/lex.go b/vendor/github.com/gorilla/sessions/lex.go
deleted file mode 100644
index 4bbbe1096de07cb9b0593feda60d90faea5ab2ba..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/lex.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// This file contains code adapted from the Go standard library
-// https://github.com/golang/go/blob/39ad0fd0789872f9469167be7fe9578625ff246e/src/net/http/lex.go
-
-package sessions
-
-import "strings"
-
-var isTokenTable = [127]bool{
-	'!':  true,
-	'#':  true,
-	'$':  true,
-	'%':  true,
-	'&':  true,
-	'\'': true,
-	'*':  true,
-	'+':  true,
-	'-':  true,
-	'.':  true,
-	'0':  true,
-	'1':  true,
-	'2':  true,
-	'3':  true,
-	'4':  true,
-	'5':  true,
-	'6':  true,
-	'7':  true,
-	'8':  true,
-	'9':  true,
-	'A':  true,
-	'B':  true,
-	'C':  true,
-	'D':  true,
-	'E':  true,
-	'F':  true,
-	'G':  true,
-	'H':  true,
-	'I':  true,
-	'J':  true,
-	'K':  true,
-	'L':  true,
-	'M':  true,
-	'N':  true,
-	'O':  true,
-	'P':  true,
-	'Q':  true,
-	'R':  true,
-	'S':  true,
-	'T':  true,
-	'U':  true,
-	'W':  true,
-	'V':  true,
-	'X':  true,
-	'Y':  true,
-	'Z':  true,
-	'^':  true,
-	'_':  true,
-	'`':  true,
-	'a':  true,
-	'b':  true,
-	'c':  true,
-	'd':  true,
-	'e':  true,
-	'f':  true,
-	'g':  true,
-	'h':  true,
-	'i':  true,
-	'j':  true,
-	'k':  true,
-	'l':  true,
-	'm':  true,
-	'n':  true,
-	'o':  true,
-	'p':  true,
-	'q':  true,
-	'r':  true,
-	's':  true,
-	't':  true,
-	'u':  true,
-	'v':  true,
-	'w':  true,
-	'x':  true,
-	'y':  true,
-	'z':  true,
-	'|':  true,
-	'~':  true,
-}
-
-func isToken(r rune) bool {
-	i := int(r)
-	return i < len(isTokenTable) && isTokenTable[i]
-}
-
-func isNotToken(r rune) bool {
-	return !isToken(r)
-}
-
-func isCookieNameValid(raw string) bool {
-	if raw == "" {
-		return false
-	}
-	return strings.IndexFunc(raw, isNotToken) < 0
-}
diff --git a/vendor/github.com/gorilla/sessions/options.go b/vendor/github.com/gorilla/sessions/options.go
deleted file mode 100644
index 38ba72fb6c2f3be835510c6bd6a066bb061d3dc2..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/options.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// +build !go1.11
-
-package sessions
-
-// Options stores configuration for a session or session store.
-//
-// Fields are a subset of http.Cookie fields.
-type Options struct {
-	Path   string
-	Domain string
-	// MaxAge=0 means no Max-Age attribute specified and the cookie will be
-	// deleted after the browser session ends.
-	// MaxAge<0 means delete cookie immediately.
-	// MaxAge>0 means Max-Age attribute present and given in seconds.
-	MaxAge   int
-	Secure   bool
-	HttpOnly bool
-}
diff --git a/vendor/github.com/gorilla/sessions/options_go111.go b/vendor/github.com/gorilla/sessions/options_go111.go
deleted file mode 100644
index 388112aad1c25a35e8bdcaf205add57a405d0b19..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/options_go111.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build go1.11
-
-package sessions
-
-import "net/http"
-
-// Options stores configuration for a session or session store.
-//
-// Fields are a subset of http.Cookie fields.
-type Options struct {
-	Path   string
-	Domain string
-	// MaxAge=0 means no Max-Age attribute specified and the cookie will be
-	// deleted after the browser session ends.
-	// MaxAge<0 means delete cookie immediately.
-	// MaxAge>0 means Max-Age attribute present and given in seconds.
-	MaxAge   int
-	Secure   bool
-	HttpOnly bool
-	// Defaults to http.SameSiteDefaultMode
-	SameSite http.SameSite
-}
diff --git a/vendor/github.com/gorilla/sessions/sessions.go b/vendor/github.com/gorilla/sessions/sessions.go
deleted file mode 100644
index c052b289112da473c649455e4232d6ee99beaefc..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/sessions.go
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sessions
-
-import (
-	"context"
-	"encoding/gob"
-	"fmt"
-	"net/http"
-	"time"
-)
-
-// Default flashes key.
-const flashesKey = "_flash"
-
-// Session --------------------------------------------------------------------
-
-// NewSession is called by session stores to create a new session instance.
-func NewSession(store Store, name string) *Session {
-	return &Session{
-		Values:  make(map[interface{}]interface{}),
-		store:   store,
-		name:    name,
-		Options: new(Options),
-	}
-}
-
-// Session stores the values and optional configuration for a session.
-type Session struct {
-	// The ID of the session, generated by stores. It should not be used for
-	// user data.
-	ID string
-	// Values contains the user-data for the session.
-	Values  map[interface{}]interface{}
-	Options *Options
-	IsNew   bool
-	store   Store
-	name    string
-}
-
-// Flashes returns a slice of flash messages from the session.
-//
-// A single variadic argument is accepted, and it is optional: it defines
-// the flash key. If not defined "_flash" is used by default.
-func (s *Session) Flashes(vars ...string) []interface{} {
-	var flashes []interface{}
-	key := flashesKey
-	if len(vars) > 0 {
-		key = vars[0]
-	}
-	if v, ok := s.Values[key]; ok {
-		// Drop the flashes and return it.
-		delete(s.Values, key)
-		flashes = v.([]interface{})
-	}
-	return flashes
-}
-
-// AddFlash adds a flash message to the session.
-//
-// A single variadic argument is accepted, and it is optional: it defines
-// the flash key. If not defined "_flash" is used by default.
-func (s *Session) AddFlash(value interface{}, vars ...string) {
-	key := flashesKey
-	if len(vars) > 0 {
-		key = vars[0]
-	}
-	var flashes []interface{}
-	if v, ok := s.Values[key]; ok {
-		flashes = v.([]interface{})
-	}
-	s.Values[key] = append(flashes, value)
-}
-
-// Save is a convenience method to save this session. It is the same as calling
-// store.Save(request, response, session). You should call Save before writing to
-// the response or returning from the handler.
-func (s *Session) Save(r *http.Request, w http.ResponseWriter) error {
-	return s.store.Save(r, w, s)
-}
-
-// Name returns the name used to register the session.
-func (s *Session) Name() string {
-	return s.name
-}
-
-// Store returns the session store used to register the session.
-func (s *Session) Store() Store {
-	return s.store
-}
-
-// Registry -------------------------------------------------------------------
-
-// sessionInfo stores a session tracked by the registry.
-type sessionInfo struct {
-	s *Session
-	e error
-}
-
-// contextKey is the type used to store the registry in the context.
-type contextKey int
-
-// registryKey is the key used to store the registry in the context.
-const registryKey contextKey = 0
-
-// GetRegistry returns a registry instance for the current request.
-func GetRegistry(r *http.Request) *Registry {
-	var ctx = r.Context()
-	registry := ctx.Value(registryKey)
-	if registry != nil {
-		return registry.(*Registry)
-	}
-	newRegistry := &Registry{
-		request:  r,
-		sessions: make(map[string]sessionInfo),
-	}
-	*r = *r.WithContext(context.WithValue(ctx, registryKey, newRegistry))
-	return newRegistry
-}
-
-// Registry stores sessions used during a request.
-type Registry struct {
-	request  *http.Request
-	sessions map[string]sessionInfo
-}
-
-// Get registers and returns a session for the given name and session store.
-//
-// It returns a new session if there are no sessions registered for the name.
-func (s *Registry) Get(store Store, name string) (session *Session, err error) {
-	if !isCookieNameValid(name) {
-		return nil, fmt.Errorf("sessions: invalid character in cookie name: %s", name)
-	}
-	if info, ok := s.sessions[name]; ok {
-		session, err = info.s, info.e
-	} else {
-		session, err = store.New(s.request, name)
-		session.name = name
-		s.sessions[name] = sessionInfo{s: session, e: err}
-	}
-	session.store = store
-	return
-}
-
-// Save saves all sessions registered for the current request.
-func (s *Registry) Save(w http.ResponseWriter) error {
-	var errMulti MultiError
-	for name, info := range s.sessions {
-		session := info.s
-		if session.store == nil {
-			errMulti = append(errMulti, fmt.Errorf(
-				"sessions: missing store for session %q", name))
-		} else if err := session.store.Save(s.request, w, session); err != nil {
-			errMulti = append(errMulti, fmt.Errorf(
-				"sessions: error saving session %q -- %v", name, err))
-		}
-	}
-	if errMulti != nil {
-		return errMulti
-	}
-	return nil
-}
-
-// Helpers --------------------------------------------------------------------
-
-func init() {
-	gob.Register([]interface{}{})
-}
-
-// Save saves all sessions used during the current request.
-func Save(r *http.Request, w http.ResponseWriter) error {
-	return GetRegistry(r).Save(w)
-}
-
-// NewCookie returns an http.Cookie with the options set. It also sets
-// the Expires field calculated based on the MaxAge value, for Internet
-// Explorer compatibility.
-func NewCookie(name, value string, options *Options) *http.Cookie {
-	cookie := newCookieFromOptions(name, value, options)
-	if options.MaxAge > 0 {
-		d := time.Duration(options.MaxAge) * time.Second
-		cookie.Expires = time.Now().Add(d)
-	} else if options.MaxAge < 0 {
-		// Set it to the past to expire now.
-		cookie.Expires = time.Unix(1, 0)
-	}
-	return cookie
-}
-
-// Error ----------------------------------------------------------------------
-
-// MultiError stores multiple errors.
-//
-// Borrowed from the App Engine SDK.
-type MultiError []error
-
-func (m MultiError) Error() string {
-	s, n := "", 0
-	for _, e := range m {
-		if e != nil {
-			if n == 0 {
-				s = e.Error()
-			}
-			n++
-		}
-	}
-	switch n {
-	case 0:
-		return "(0 errors)"
-	case 1:
-		return s
-	case 2:
-		return s + " (and 1 other error)"
-	}
-	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
-}
diff --git a/vendor/github.com/gorilla/sessions/store.go b/vendor/github.com/gorilla/sessions/store.go
deleted file mode 100644
index bb7f9647d6d15c8c17a13d4031b36f42aab1143f..0000000000000000000000000000000000000000
--- a/vendor/github.com/gorilla/sessions/store.go
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sessions
-
-import (
-	"encoding/base32"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"path/filepath"
-	"strings"
-	"sync"
-
-	"github.com/gorilla/securecookie"
-)
-
-// Store is an interface for custom session stores.
-//
-// See CookieStore and FilesystemStore for examples.
-type Store interface {
-	// Get should return a cached session.
-	Get(r *http.Request, name string) (*Session, error)
-
-	// New should create and return a new session.
-	//
-	// Note that New should never return a nil session, even in the case of
-	// an error if using the Registry infrastructure to cache the session.
-	New(r *http.Request, name string) (*Session, error)
-
-	// Save should persist session to the underlying store implementation.
-	Save(r *http.Request, w http.ResponseWriter, s *Session) error
-}
-
-// CookieStore ----------------------------------------------------------------
-
-// NewCookieStore returns a new CookieStore.
-//
-// Keys are defined in pairs to allow key rotation, but the common case is
-// to set a single authentication key and optionally an encryption key.
-//
-// The first key in a pair is used for authentication and the second for
-// encryption. The encryption key can be set to nil or omitted in the last
-// pair, but the authentication key is required in all pairs.
-//
-// It is recommended to use an authentication key with 32 or 64 bytes.
-// The encryption key, if set, must be either 16, 24, or 32 bytes to select
-// AES-128, AES-192, or AES-256 modes.
-func NewCookieStore(keyPairs ...[]byte) *CookieStore {
-	cs := &CookieStore{
-		Codecs: securecookie.CodecsFromPairs(keyPairs...),
-		Options: &Options{
-			Path:   "/",
-			MaxAge: 86400 * 30,
-		},
-	}
-
-	cs.MaxAge(cs.Options.MaxAge)
-	return cs
-}
-
-// CookieStore stores sessions using secure cookies.
-type CookieStore struct {
-	Codecs  []securecookie.Codec
-	Options *Options // default configuration
-}
-
-// Get returns a session for the given name after adding it to the registry.
-//
-// It returns a new session if the sessions doesn't exist. Access IsNew on
-// the session to check if it is an existing session or a new one.
-//
-// It returns a new session and an error if the session exists but could
-// not be decoded.
-func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) {
-	return GetRegistry(r).Get(s, name)
-}
-
-// New returns a session for the given name without adding it to the registry.
-//
-// The difference between New() and Get() is that calling New() twice will
-// decode the session data twice, while Get() registers and reuses the same
-// decoded session after the first call.
-func (s *CookieStore) New(r *http.Request, name string) (*Session, error) {
-	session := NewSession(s, name)
-	opts := *s.Options
-	session.Options = &opts
-	session.IsNew = true
-	var err error
-	if c, errCookie := r.Cookie(name); errCookie == nil {
-		err = securecookie.DecodeMulti(name, c.Value, &session.Values,
-			s.Codecs...)
-		if err == nil {
-			session.IsNew = false
-		}
-	}
-	return session, err
-}
-
-// Save adds a single session to the response.
-func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter,
-	session *Session) error {
-	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
-		s.Codecs...)
-	if err != nil {
-		return err
-	}
-	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
-	return nil
-}
-
-// MaxAge sets the maximum age for the store and the underlying cookie
-// implementation. Individual sessions can be deleted by setting Options.MaxAge
-// = -1 for that session.
-func (s *CookieStore) MaxAge(age int) {
-	s.Options.MaxAge = age
-
-	// Set the maxAge for each securecookie instance.
-	for _, codec := range s.Codecs {
-		if sc, ok := codec.(*securecookie.SecureCookie); ok {
-			sc.MaxAge(age)
-		}
-	}
-}
-
-// FilesystemStore ------------------------------------------------------------
-
-var fileMutex sync.RWMutex
-
-// NewFilesystemStore returns a new FilesystemStore.
-//
-// The path argument is the directory where sessions will be saved. If empty
-// it will use os.TempDir().
-//
-// See NewCookieStore() for a description of the other parameters.
-func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore {
-	if path == "" {
-		path = os.TempDir()
-	}
-	fs := &FilesystemStore{
-		Codecs: securecookie.CodecsFromPairs(keyPairs...),
-		Options: &Options{
-			Path:   "/",
-			MaxAge: 86400 * 30,
-		},
-		path: path,
-	}
-
-	fs.MaxAge(fs.Options.MaxAge)
-	return fs
-}
-
-// FilesystemStore stores sessions in the filesystem.
-//
-// It also serves as a reference for custom stores.
-//
-// This store is still experimental and not well tested. Feedback is welcome.
-type FilesystemStore struct {
-	Codecs  []securecookie.Codec
-	Options *Options // default configuration
-	path    string
-}
-
-// MaxLength restricts the maximum length of new sessions to l.
-// If l is 0 there is no limit to the size of a session, use with caution.
-// The default for a new FilesystemStore is 4096.
-func (s *FilesystemStore) MaxLength(l int) {
-	for _, c := range s.Codecs {
-		if codec, ok := c.(*securecookie.SecureCookie); ok {
-			codec.MaxLength(l)
-		}
-	}
-}
-
-// Get returns a session for the given name after adding it to the registry.
-//
-// See CookieStore.Get().
-func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) {
-	return GetRegistry(r).Get(s, name)
-}
-
-// New returns a session for the given name without adding it to the registry.
-//
-// See CookieStore.New().
-func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) {
-	session := NewSession(s, name)
-	opts := *s.Options
-	session.Options = &opts
-	session.IsNew = true
-	var err error
-	if c, errCookie := r.Cookie(name); errCookie == nil {
-		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
-		if err == nil {
-			err = s.load(session)
-			if err == nil {
-				session.IsNew = false
-			}
-		}
-	}
-	return session, err
-}
-
-// Save adds a single session to the response.
-//
-// If the Options.MaxAge of the session is <= 0 then the session file will be
-// deleted from the store path. With this process it enforces the properly
-// session cookie handling so no need to trust in the cookie management in the
-// web browser.
-func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
-	session *Session) error {
-	// Delete if max-age is <= 0
-	if session.Options.MaxAge <= 0 {
-		if err := s.erase(session); err != nil {
-			return err
-		}
-		http.SetCookie(w, NewCookie(session.Name(), "", session.Options))
-		return nil
-	}
-
-	if session.ID == "" {
-		// Because the ID is used in the filename, encode it to
-		// use alphanumeric characters only.
-		session.ID = strings.TrimRight(
-			base32.StdEncoding.EncodeToString(
-				securecookie.GenerateRandomKey(32)), "=")
-	}
-	if err := s.save(session); err != nil {
-		return err
-	}
-	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
-		s.Codecs...)
-	if err != nil {
-		return err
-	}
-	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
-	return nil
-}
-
-// MaxAge sets the maximum age for the store and the underlying cookie
-// implementation. Individual sessions can be deleted by setting Options.MaxAge
-// = -1 for that session.
-func (s *FilesystemStore) MaxAge(age int) {
-	s.Options.MaxAge = age
-
-	// Set the maxAge for each securecookie instance.
-	for _, codec := range s.Codecs {
-		if sc, ok := codec.(*securecookie.SecureCookie); ok {
-			sc.MaxAge(age)
-		}
-	}
-}
-
-// save writes encoded session.Values to a file.
-func (s *FilesystemStore) save(session *Session) error {
-	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
-		s.Codecs...)
-	if err != nil {
-		return err
-	}
-	filename := filepath.Join(s.path, "session_"+session.ID)
-	fileMutex.Lock()
-	defer fileMutex.Unlock()
-	return ioutil.WriteFile(filename, []byte(encoded), 0600)
-}
-
-// load reads a file and decodes its content into session.Values.
-func (s *FilesystemStore) load(session *Session) error {
-	filename := filepath.Join(s.path, "session_"+session.ID)
-	fileMutex.RLock()
-	defer fileMutex.RUnlock()
-	fdata, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return err
-	}
-	if err = securecookie.DecodeMulti(session.Name(), string(fdata),
-		&session.Values, s.Codecs...); err != nil {
-		return err
-	}
-	return nil
-}
-
-// delete session file
-func (s *FilesystemStore) erase(session *Session) error {
-	filename := filepath.Join(s.path, "session_"+session.ID)
-
-	fileMutex.RLock()
-	defer fileMutex.RUnlock()
-
-	err := os.Remove(filename)
-	return err
-}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 02e412820d9f5bf6fa27aa7a57f88cb8babe59eb..106fa139c100e774ea5421110d946256dcbc59de 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -134,12 +134,6 @@
 			"revision": "61b4ad17eb88d0d1118560d1101176279be2bc88",
 			"revisionTime": "2019-10-28T04:23:04Z"
 		},
-		{
-			"checksumSHA1": "cwc8hi1B7gYshKGFEEhrsvSUsxU=",
-			"path": "github.com/gorilla/sessions",
-			"revision": "400b592ab70b9f8ee876cf47bc6c794d255dd4aa",
-			"revisionTime": "2019-10-06T15:13:01Z"
-		},
 		{
 			"checksumSHA1": "SGc5vSs9tXhrGJ5ncymDyMvTg24=",
 			"path": "github.com/jonboulle/clockwork",