SCS: A session manager for Go 1.7+

I’ve just released SCS, a session management package for Go 1.7+. You can view it on Github.

Its design leverages Go’s new context package to automatically load and save session data via middleware.

Importantly, it also provides the security features that you need when using server-side session stores (like straightforward session token regeneration) and supports both absolute and inactivity timeouts. The session data is safe for concurrent use.

A simple example

SCS supports a variety of different session stores and is broken up into small single-purpose packages for ease of use.

Package
scs Provides session management middleware and helpers for manipulating session data
scs/stores/boltstoreBoltDB based session store
scs/stores/buntstoreBuntDB based session store
scs/stores/cookiestoreEncrypted-cookie based session store
scs/stores/dynamostoreDynamoDB based session store
scs/stores/memstoreIn-memory session store
scs/stores/mysqlstoreMySQL based session store
scs/stores/pgstorePostgreSQL based session store
scs/stores/qlstoreQL based session store
scs/stores/redisstoreRedis based session store

To use the in-memory store, for example:

File: main.go
package main

import (
    "io"
    "net/http"
    "time"

    "github.com/alexedwards/scs"
    "github.com/alexedwards/scs/stores/memstore"
)

// Initialize a new encrypted-cookie based session manager and store it in a
// global variable. In a real application, you might inject the session
// manager as a dependency to your handlers instead.
var sessionManager *scs.Manager

func main() {
    // Establish a session manager using the in-memory store and configure
    // it's behaviour.
    sessionManager = scs.NewManager(memstore.New(0))
    sessionManager.Lifetime(3 * time.Hour)
    sessionManager.Persist(true)

    // Set up your HTTP handlers in the normal way.
    mux := http.NewServeMux()
    mux.HandleFunc("/put", putHandler)
    mux.HandleFunc("/get", getHandler)

    // Wrap your handlers with the session manager middleware.
    http.ListenAndServe(":4000", sessionManager.Use(mux))
}

func putHandler(w http.ResponseWriter, r *http.Request) {
    // Load the session data for the current request. Any errors are deferred
    // until you actually use the session data.
    session := sessionManager.Load(r)

    // Use the PutString() method to add a new key and associated string
    // value to the session data. Methods for many other common data types
    // are also provided. The session data is automatically saved.
    err := session.PutString(w, "message", "Hello world!")
    if err != nil {
        http.Error(w, err.Error(), 500)
    }
}

func getHandler(w http.ResponseWriter, r *http.Request) {
    // Load the session data for the current request.
    session := sessionManager.Load(r)

    // Use the GetString() helper to retrieve the string value for the
    // "message" key from the session data. The zero value for a string is
    // returned if the key does not exist.
    message, err := session.GetString("message")
    if err != nil {
        http.Error(w, err.Error(), 500)
    }

    io.WriteString(w, message)
}

You should be able to verify that the session data is being across requests with curl:

$ curl -i -c cookies localhost:4000/put
HTTP/1.1 200 OK
Set-Cookie: session=Z37PlmuLf51lFeVIce3Ed7Q4j1Jz_w2w7B2ZrACZ7ds; Path=/; Expires=Tue, 10 Oct 2017 17:02:53 GMT; Max-Age=10800; HttpOnly
Date: Tue, 10 Oct 2017 14:02:52 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8

$ curl -i -b cookies localhost:4000/get
HTTP/1.1 200 OK
Date: Tue, 10 Oct 2017 14:03:20 GMT
Content-Length: 12
Content-Type: text/plain; charset=utf-8

Hello world!

The complete godocs are here.

I’d love to hear any feedback – either drop me an email or open an issue on Github.