Help us shape the future of Go! Take the 2026 Go Developer Survey

browsersession

package
v1.125.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package browsersession provides browser-based OIDC authentication and cookie-managed sessions for the portal UI. It implements:

  • HMAC-SHA256 signed JWT session cookies (stateless)
  • OIDC authorization code flow with PKCE
  • Cookie-based authenticator for the HTTP auth chain

Index

Constants

View Source
const (
	DefaultCookieName = "mcp_session"
	DefaultCookiePath = "/"
	DefaultTTL        = 8 * time.Hour
)

Default configuration values.

View Source
const CSRFHeaderName = "X-CSRF-Token" //nolint:gosec // header name, not a credential

CSRFHeaderName is the request header that carries the CSRF token on state-changing requests authenticated by a session cookie. Because it is a custom header, a cross-origin page cannot set it on a form/navigation submit, and the browser blocks scripted cross-origin reads of the token, so only same-origin callers that legitimately fetched the token can send a valid value.

View Source
const DefaultPortalPath = "/portal/"

DefaultPortalPath is the default redirect path for the portal UI.

Variables

View Source
var ErrCSRFInvalid = errors.New("missing or invalid CSRF token")

ErrCSRFInvalid is returned when a cookie-authenticated, state-changing request is missing a valid X-CSRF-Token header.

Functions

func ClearCookie

func ClearCookie(w http.ResponseWriter, cfg *CookieConfig)

ClearCookie removes the session cookie.

func IsValidSameSite added in v1.96.0

func IsValidSameSite(s string) bool

IsValidSameSite reports whether s is a recognized same_site config value (case-insensitive): "" (defaults to Lax), "lax", "strict", or "none". Config validation uses this to reject a typo at startup rather than let ParseSameSite silently downgrade an unrecognized value to Lax.

func ParseSameSite added in v1.96.0

func ParseSameSite(s string) http.SameSite

ParseSameSite maps a configuration string ("lax", "strict", "none") to an http.SameSite mode. An empty or unrecognized value yields the zero value, which effectiveSameSite treats as Lax, the safe default. The match is case-insensitive.

func SetCookie

func SetCookie(w http.ResponseWriter, cfg *CookieConfig, tokenString string)

SetCookie writes the session JWT as an HTTP-only cookie.

func SignSession

func SignSession(claims SessionClaims, cfg *CookieConfig) (string, error)

SignSession creates a signed JWT string from session claims.

Types

type Authenticator

type Authenticator struct {
	// contains filtered or unexported fields
}

Authenticator checks for a valid session cookie and returns user info. It is designed to be used as the first step in an HTTP auth chain — if no cookie is present or the cookie is invalid, it returns nil (allowing fallback to token-based authentication).

func NewAuthenticator

func NewAuthenticator(cfg CookieConfig) *Authenticator

NewAuthenticator creates a cookie-based authenticator.

func (*Authenticator) AuthenticateHTTP

func (a *Authenticator) AuthenticateHTTP(r *http.Request) (*middleware.UserInfo, error)

AuthenticateHTTP checks the HTTP request for a valid session cookie. Returns nil, nil when no valid cookie is found (no error, just unauthenticated).

func (*Authenticator) ExtractIDToken added in v0.36.2

func (a *Authenticator) ExtractIDToken(r *http.Request) string

ExtractIDToken extracts the OIDC id_token from the session cookie. Returns empty string if no valid session exists or no id_token is stored.

func (*Authenticator) IssueCSRFToken added in v1.96.0

func (a *Authenticator) IssueCSRFToken(subject string) string

IssueCSRFToken derives a stateless CSRF token bound to the session subject.

The token is an HMAC-SHA256 of the subject under the same signing key that protects the session cookie, so it needs no server-side storage and is verified by recomputation. It is safe to hand to the browser (e.g. in the /me response) because an attacker on another origin can neither read the same-origin response body (blocked by the browser) nor forge the HMAC without the signing key.

func (*Authenticator) ValidateCSRFRequest added in v1.96.0

func (a *Authenticator) ValidateCSRFRequest(r *http.Request, subject string) error

ValidateCSRFRequest enforces CSRF protection for a cookie-authenticated request. Safe (read-only) methods always pass. State-changing methods must carry an X-CSRF-Token header whose value matches the token bound to subject; otherwise ErrCSRFInvalid is returned.

Token-authenticated (API-key / Bearer) requests do not reach this check — they are not vulnerable to CSRF because the credential is not attached automatically by the browser.

type CookieConfig

type CookieConfig struct {
	// Name is the cookie name (default: "mcp_session").
	Name string

	// Domain restricts the cookie to a specific domain.
	Domain string

	// Path restricts the cookie to a specific path (default: "/").
	Path string

	// Secure marks the cookie as HTTPS-only (default: true).
	Secure bool

	// SameSite controls cross-site cookie behavior (default: Lax).
	SameSite http.SameSite

	// TTL is the session lifetime (default: 8h).
	TTL time.Duration

	// Key is the HMAC-SHA256 signing key. Must be at least 32 bytes.
	Key []byte
}

CookieConfig controls session cookie behavior.

func (*CookieConfig) IsCrossSiteCookieMode added in v1.96.0

func (c *CookieConfig) IsCrossSiteCookieMode() bool

IsCrossSiteCookieMode reports whether the effective SameSite setting permits cross-site transmission of the session cookie (SameSite=None). In that mode the browser's built-in CSRF defense is disabled and the X-CSRF-Token layer becomes the sole protection, so callers should log a startup warning.

type Flow

type Flow struct {
	// contains filtered or unexported fields
}

Flow implements the OIDC authorization code flow with PKCE.

func NewFlow

func NewFlow(ctx context.Context, cfg FlowConfig) (*Flow, error)

NewFlow creates a new OIDC flow by performing provider discovery.

func (*Flow) CallbackHandler

func (f *Flow) CallbackHandler(w http.ResponseWriter, r *http.Request)

CallbackHandler processes the OIDC provider's callback after authentication. It validates the state, exchanges the authorization code for tokens, creates a session cookie, and redirects to the portal.

func (*Flow) LoginHandler

func (f *Flow) LoginHandler(w http.ResponseWriter, r *http.Request)

LoginHandler initiates the OIDC authorization code flow. It generates state + PKCE verifier, stores them in a temporary cookie, and redirects the user to the OIDC provider's authorization endpoint.

An optional `return_to` query parameter is captured into the state cookie and used as the post-login redirect on callback. This lets the admin SPA send a 401-recovery flow back to the page the operator was on (e.g., a connection settings page where they clicked Connect) rather than dropping them at the portal root. The value must be a site-relative path; anything else is silently dropped so an attacker can't dangle an open redirect off the login endpoint.

func (*Flow) LogoutHandler

func (f *Flow) LogoutHandler(w http.ResponseWriter, r *http.Request)

LogoutHandler clears the session cookie and redirects to the OIDC end_session endpoint.

type FlowConfig

type FlowConfig struct {
	// Issuer is the OIDC provider's issuer URL.
	Issuer string

	// ClientID is the OIDC client identifier.
	ClientID string

	// ClientSecret is the OIDC client secret for confidential clients.
	ClientSecret string // #nosec G117 -- OIDC client secret from admin config

	// RedirectURI is the callback URL (e.g., "https://example.com/portal/auth/callback").
	RedirectURI string

	// Scopes to request (default: [openid, profile, email]).
	Scopes []string

	// RoleClaim is the JSON path to roles in the id_token claims.
	RoleClaim string

	// RolePrefix filters roles to those with this prefix.
	RolePrefix string

	// Cookie configures the session cookie.
	Cookie CookieConfig

	// PostLoginRedirect is where to redirect after successful login (default: DefaultPortalPath).
	PostLoginRedirect string

	// PostLogoutRedirect is the absolute URL sent as post_logout_redirect_uri
	// to the OIDC provider. Must be an absolute URL (Keycloak rejects relative paths).
	// Falls back to PostLoginRedirect if empty.
	PostLogoutRedirect string

	// HTTPClient is used for OIDC discovery and token exchange.
	// If nil, http.DefaultClient is used.
	HTTPClient *http.Client

	// OnLogin, if set, is called after a successful login with the person's
	// email and name derived from the id_token. It records browser-session
	// (portal/admin SPA) users in the known-users directory (#614). It must be
	// non-blocking and best-effort — login must never depend on it.
	OnLogin func(email, firstName, lastName string)
}

FlowConfig configures the OIDC authorization code flow.

type SessionClaims

type SessionClaims struct {
	UserID  string   `json:"sub"`
	Email   string   `json:"email,omitempty"`
	Roles   []string `json:"roles"`
	IDToken string   `json:"idt,omitempty"` // raw id_token for logout id_token_hint

	// FirstName and LastName are derived from the id_token at login and used to
	// record the person in the known-users directory (#614). They are NOT
	// persisted in the session cookie (json:"-"); they exist only in-memory for
	// the duration of the callback, so the cookie stays small and these are
	// absent on subsequent cookie-authenticated requests.
	FirstName string `json:"-"`
	LastName  string `json:"-"`
}

SessionClaims holds the claims stored in the session JWT cookie.

func ParseFromRequest

func ParseFromRequest(r *http.Request, cfg *CookieConfig) (*SessionClaims, error)

ParseFromRequest reads the session cookie from the request and verifies it.

func VerifySession

func VerifySession(tokenString string, key []byte) (*SessionClaims, error)

VerifySession validates a signed JWT and returns the session claims.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL