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.

Implement the Session Manager

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. It 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
}

The following code example is a lightweight implementation of a SessionManager using github.com/gorilla/sessions that you can use in your own project.

  1. First, run the following to download the Gorilla sessions library:
go get github.com/gorilla/sessions
  1. Then copy this implementation into your project (e.g. session.go):
// 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 NewSessionStore(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 SessionManager implementation, you'll use it to create a Wristband app instance. You'll need to provide a 32-character secret as the secret value. You can generate a secure secret key at https://securepassword.dev.

⚙️

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

package main

import (
  "github.com/wristband-dev/go-auth"
)

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

  // ADD: Create session manager
  sessionManager := NewSessionStore("<your-generated-secret>", true)

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

package main

import (
  "github.com/wristband-dev/go-auth"
)

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

  // ADD: Create session manager
  sessionManager := NewSessionStore("<your-generated-secret>", false)

  // ADD: 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 auth middleware needed to secure your application.