Add Session Management

Set up session middleware to manage your application's authenticated sessions.

To manage the user's authenticated state, you'll need to implement a session manager for your application. Unlike other Wristband SDKs that provide built-in session middleware, the Go SDK is unopinionated about session storage, giving you full control over how sessions are stored and managed.

The SDK defines a SessionManager interface that you need to implement. The session data is typically stored in an encrypted cookie, and on subsequent requests, the middleware decrypts the cookie and restores the session state.

Session Manager Interface

The SessionManager interface defines three methods that your implementation must provide:

type SessionManager interface {
    StoreSession(w http.ResponseWriter, r *http.Request, session *goauth.Session) error
    GetSession(r *http.Request) (*goauth.Session, error)
    ClearSession(w http.ResponseWriter, r *http.Request) error
}

Lightweight Cookie Session Manager

Here is a minimal implementation of a SessionManager implementation using github.com/gorilla/securecookie and github.com/gorilla/sessions.

Run the following

go get github.com/gorilla/sessions

Code

// session.go

package main

import (
    "encoding/json"
    "errors"
    "net/http"

    "github.com/gorilla/sessions"
    goauth "github.com/wristband-dev/go-auth"
)

const (
    // SessionName is the name used for the session cookie
    SessionName = "session"

    // SessionKey is the key used to store auth data in the session
    SessionKey = "auth_session"
)

// GorillaSessionManager implements the goauth.SessionManager interface
// using gorilla/sessions for session management
type GorillaSessionManager struct {
    store sessions.Store
}

func NewStore(secret []byte, secureCookies bool) goauth.SessionManager {
    store := sessions.NewCookieStore(secret, nil)
    store.Options.Secure = secureCookies
    store.Options.HttpOnly = true
    store.Options.SameSite = http.SameSiteLaxMode
    return &GorillaSessionManager{
        store: store,
    }
}

// StoreSession implements the goauth.SessionManager interface
func (m *GorillaSessionManager) StoreSession(w http.ResponseWriter, r *http.Request, session *goauth.Session) error {
    // Get existing session or create a new one
    sess, err := m.store.Get(r, SessionName)
    if err != nil {
        // If there's an error getting the session, create a new one
        // This can happen if the session was tampered with or is invalid
        sess, err = m.store.New(r, SessionName)
        if err != nil {
             return err
        }
    }

    // Serialize the session to JSON
    sessionJSON, err := json.Marshal(session)
    if err != nil {
        return err
    }

    // Store the serialized session in the session store
    sess.Values[SessionKey] = string(sessionJSON)

    // Save the session
    return sess.Save(r, w)
}

// GetSession implements the goauth.SessionManager interface
func (m *GorillaSessionManager) GetSession(r *http.Request) (*goauth.Session, error) {
    // Get existing session
    sess, err := m.store.Get(r, SessionName)
    if err != nil {
        return nil, err
    }

    // Check if the session contains auth data
    sessionJSON, ok := sess.Values[SessionKey]
    if !ok {
        return nil, errors.New("no auth session found")
    }

    // Parse the serialized session
    var authSession goauth.Session
    err = json.Unmarshal([]byte(sessionJSON.(string)), &authSession)
    if err != nil {
        return nil, err
    }

    return &authSession, nil
}

// ClearSession implements the goauth.SessionManager interface
func (m *GorillaSessionManager) ClearSession(w http.ResponseWriter, r *http.Request) error {
    // Get existing session
    sess, err := m.store.Get(r, SessionName)
    if err != nil {
        // If we can't get the session, that's fine - we wanted to clear it anyway
        return nil
    }

    // Remove the auth data from the session
    delete(sess.Values, SessionKey)

    // Set session to expire
    sess.Options.MaxAge = -1

    // Save the session
    return sess.Save(r, w)
}

Register the Session Manager

After creating your session manager implementation, you'll use it when creating the Wristband app instance:

⚠️

Important: You must provide a 32-byte secret for encryption. You can generate a secure secret using 1Password's password generator .

⚙️

Disabling Secure Session Cookies in Local Development

By default, session cookies are marked as secure, meaning they are only sent over HTTPS connections. Most browsers make an exception for localhost and allow secure cookies to be sent over HTTP (e.g., http://localhost). However, some browsers, such as Safari, enforce stricter rules and never send secure cookies over HTTP, even for localhost.

If you need to disable the secure flag for local development, set secure: false in your session options. However, be sure to restore secure: true in production to protect session data.

// main.go

func main() {
  cfg := goauth.NewAuthConfig(
    "<WRISTBAND_CLIENT_ID>",
    "<WRISTBAND_CLIENT_SECRET>",
    "<WRISTBAND_APPLICATION_VANITY_DOMAIN>",
  )
  auth, err := cfg.WristbandAuth()
  if err != nil {
    // Handle error
  }

  // Create session manager
  secret := os.Getenv("SESSION_SECRET")
  sessionManager, err := NewCookieSessionManager(secret, true)
  if err != nil {
    log.Fatal(err)
  }

  // Create the Wristband app with the session manager
  app := wristbandAuth.NewApp(sessionManager)
}
// main.go

func main() {
  cfg := goauth.NewAuthConfig(
    "<WRISTBAND_CLIENT_ID>",
    "<WRISTBAND_CLIENT_SECRET>",
    "<WRISTBAND_APPLICATION_VANITY_DOMAIN>",
    goauth.WithDangerouslyDisableSecureCookies(),
  )
  auth, err := cfg.WristbandAuth()
  if err != nil {
    // Handle error
  }

  // Create session manager
  secret := os.Getenv("SESSION_SECRET")
  sessionManager, err := NewCookieSessionManager(secret, false)
  if err != nil {
    log.Fatal(err)
  }

  // Create the Wristband app with the session manager
  app := wristbandAuth.NewApp(sessionManager)
}


What’s Next

Next, you'll use the Wristband SDK to create the necessary authentication endpoints in your Go server.