httpauth

package
v0.0.72 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const DefaultMaxBodySize = 1 << 20 // 1MB

DefaultMaxBodySize is the default request body size limit (1MB).

Variables

This section is empty.

Functions

func CSRFTemplateField

func CSRFTemplateField(r *http.Request) template.HTML

CSRFTemplateField returns an HTML hidden input field containing the CSRF token. Use this in templates: {{.CSRFField}}

func CSRFToken

func CSRFToken(r *http.Request) string

CSRFToken extracts the CSRF token from the request context. Returns an empty string if the CSRF middleware is not active.

func IsBodyTooLargeError added in v0.0.42

func IsBodyTooLargeError(err error) bool

IsBodyTooLargeError checks if an error is from http.MaxBytesReader exceeding its limit.

func LimitBody added in v0.0.42

func LimitBody(maxBytes int64) func(http.Handler) http.Handler

LimitBody returns middleware that limits the request body to maxBytes. If the body exceeds the limit, a 413 Request Entity Too Large response is sent before the handler runs. This prevents memory exhaustion from oversized JSON bodies (CWE-400: Uncontrolled Resource Consumption).

Usage:

mux.Handle("/api/login", httpauth.LimitBody(1<<20)(loginHandler))

Or wrap an entire mux:

http.ListenAndServe(":8080", httpauth.LimitBody(1<<20)(mux))

func LimitBodyReader added in v0.0.42

func LimitBodyReader(w http.ResponseWriter, r *http.Request, maxBytes int64)

LimitBodyReader is a lower-level helper that wraps a request body with http.MaxBytesReader. Unlike LimitBody middleware, it doesn't reject upfront — the error occurs when the handler tries to read past the limit. Use this when you need to apply limits inside a handler rather than as middleware.

func SecurityHeaders added in v0.0.43

func SecurityHeaders() func(http.Handler) http.Handler

SecurityHeaders returns middleware that sets standard security headers on every response. These headers protect against common web vulnerabilities:

  • HSTS: forces HTTPS connections (RFC 6797)
  • X-Content-Type-Options: prevents MIME sniffing
  • X-Frame-Options: prevents clickjacking
  • Content-Security-Policy: mitigates XSS
  • Referrer-Policy: controls referrer leakage
  • Permissions-Policy: disables unnecessary browser APIs

Usage:

mux := http.NewServeMux()
handler := httpauth.SecurityHeaders()(mux)
http.ListenAndServe(":8080", handler)

See: https://owasp.org/www-project-secure-headers/

func SecurityHeadersWithConfig added in v0.0.43

func SecurityHeadersWithConfig(cfg SecurityHeadersConfig) func(http.Handler) http.Handler

SecurityHeadersWithConfig returns middleware using the provided configuration.

Types

type AuthUserStore

type AuthUserStore interface {
	core.UserStore
	core.IdentityStore
	core.ChannelStore

	// EnsureAuthUser orchestrates user creation/lookup across stores
	// This is the main entry point for OAuth and local authentication
	EnsureAuthUser(authtype string, provider string, token *oauth2.Token, userInfo map[string]any) (core.User, error)
}

AuthUserStore combines the store interfaces needed for authentication

type CSRFMiddleware

type CSRFMiddleware struct {
	// CookieName is the name of the CSRF cookie. Default: "csrf_token".
	CookieName string
	// FieldName is the form field name to check. Default: "csrf_token".
	FieldName string
	// HeaderName is the HTTP header to check. Default: "X-CSRF-Token".
	HeaderName string
	// MaxAge is the cookie lifetime in seconds. Default: 3600 (1 hour).
	MaxAge int
	// Secure sets the Secure flag on the cookie (for HTTPS).
	Secure bool
	// SameSite sets the SameSite attribute. Default: SameSiteStrictMode.
	SameSite http.SameSite
	// Path sets the cookie path. Default: "/".
	Path string
	// ErrorHandler is called when CSRF validation fails. Default: 403 JSON response.
	ErrorHandler http.HandlerFunc
	// ExemptFunc returns true if the request should skip CSRF validation.
	// Default: exempt requests with an Authorization: Bearer header.
	ExemptFunc func(*http.Request) bool
}

CSRFMiddleware implements the double-submit cookie pattern for CSRF protection. It generates a random token stored in a cookie and validates that state-changing requests include a matching token in a form field or header.

Bearer-token requests are exempt by default since they are not vulnerable to CSRF. The cookie is NOT HttpOnly so JavaScript can read it for AJAX header submission.

func (*CSRFMiddleware) Protect

func (m *CSRFMiddleware) Protect(next http.Handler) http.Handler

Protect returns middleware that enforces CSRF protection. Safe methods (GET, HEAD, OPTIONS) receive a CSRF cookie and have the token injected into the request context. Unsafe methods must include a matching token in either the form field or header.

type LinkOAuthConfig

type LinkOAuthConfig struct {
	UserStore     core.UserStore
	IdentityStore core.IdentityStore
	ChannelStore  core.ChannelStore
}

LinkOAuthConfig holds configuration for OAuth account linking

type Middleware

type Middleware struct {
	AuthTokenHeaderName string
	AuthTokenCookieName string
	UserParamName       string
	CallbackURLParam    string
	SessionGetter       func(r *http.Request, param string) any
	GetRedirURL         func(r *http.Request) string
	DefaultRedirectURL  string
	VerifyToken         func(tokenString string) (loggedInUserId string, token any, err error)
}

func (*Middleware) EnsureReasonableDefaults

func (a *Middleware) EnsureReasonableDefaults()

*

  • Ensures that config values have reasonable defaults.

func (*Middleware) EnsureUser

func (a *Middleware) EnsureUser(next http.Handler) http.Handler

func (*Middleware) ExtractUser

func (a *Middleware) ExtractUser(next http.Handler) http.Handler

*

  • Fetches the user from the request and loads the UserId and User variables
  • available for other handlers. *
  • Note this does not perform any redirects if a valid user does not exist.
  • To also enforce a user exists, use the EnsureUser handler which both
  • calls ExgractUser and ensures that user is logged in.

func (*Middleware) GetLoggedInUserId

func (a *Middleware) GetLoggedInUserId(r *http.Request) string

Get the ID of the logged in user from the current request

type OneAuth

type OneAuth struct {
	Session    *scs.SessionManager
	Middleware Middleware

	// Optional name that can be used as a prefix for all required vars
	AppName string

	// Name of the session variable where the auth token is stored
	AuthTokenSessionVar string

	// Must be passed in
	UserStore AuthUserStore

	// All the domains where the auth token cookies will be set on a login success or logout
	CookieDomains []string

	// JWT related fields
	JwtIssuer    string
	JWTSecretKey string

	// How long is a session cookie valid for.  Defaults to 1 day
	SessionTimeoutInSeconds int
	// contains filtered or unexported fields
}

func New

func New(appName string) *OneAuth

func (*OneAuth) AddAuth

func (a *OneAuth) AddAuth(prefix string, handler http.Handler) *OneAuth

func (*OneAuth) EnsureDefaults

func (a *OneAuth) EnsureDefaults() *OneAuth

func (*OneAuth) GetLinkingUserID

func (a *OneAuth) GetLinkingUserID(r *http.Request) string

GetLinkingUserID retrieves and clears the linking user ID from session. Call this in your OAuth callback to detect linking mode.

Example Usage

func googleCallback(w http.ResponseWriter, r *http.Request) {
    linkingUserID := oneAuth.GetLinkingUserID(r)
    if linkingUserID != "" {
        // Linking flow
        oneAuth.HandleLinkOAuthCallback(config, linkingUserID, "google", userInfo, w, r)
        return
    }
    // Normal login flow
    oneAuth.SaveUserAndRedirect(...)
}

func (*OneAuth) HandleLinkOAuthCallback

func (a *OneAuth) HandleLinkOAuthCallback(config LinkOAuthConfig, linkingUserID, provider string, userInfo map[string]any, w http.ResponseWriter, r *http.Request)

HandleLinkOAuthCallback returns an HTTP handler for linking an OAuth provider to an existing local-only user.

Who Calls This

This is called by OAuth providers after the user authorizes linking. The flow is:

  1. Local-only user visits profile, clicks "Link Google Account"
  2. App stores user ID in session as "linkingUserID"
  3. App redirects to Google OAuth with special state
  4. Google redirects back to /auth/google/callback
  5. OAuth callback sees "linkingUserID" in session
  6. Instead of normal login, calls this handler to link the account

How to Set Up

Modify your OAuth callback to detect linking mode:

func googleCallback(w http.ResponseWriter, r *http.Request) {
    // ... exchange code for token, get userInfo ...

    // Check if this is a linking flow
    linkingUserID := session.Get("linkingUserID")
    if linkingUserID != "" {
        session.Delete("linkingUserID")
        linkConfig := oneauth.LinkOAuthConfig{
            UserStore:     stores.UserStore,
            IdentityStore: stores.IdentityStore,
            ChannelStore:  stores.ChannelStore,
        }
        oneAuth.HandleLinkOAuthCallback(linkConfig, linkingUserID, "google", userInfo, w, r)
        return
    }

    // Normal login flow
    oneAuth.SaveUserAndRedirect("oauth", "google", token, userInfo, w, r)
}

What It Does

  1. Verifies the OAuth email matches the user's existing email identity
  2. Creates OAuth channel for the provider
  3. Updates user profile["channels"] to include the new provider
  4. Redirects to callback URL (or returns JSON success)

Security

The OAuth email MUST match the user's existing email to prevent account hijacking. Users cannot link to a different email address.

func (*OneAuth) Handler

func (a *OneAuth) Handler() http.Handler

func (*OneAuth) SaveUserAndRedirect

func (a *OneAuth) SaveUserAndRedirect(authtype, provider string, token *oauth2.Token, userInfo map[string]any, w http.ResponseWriter, r *http.Request)

*

  • Called by the oauth callback handler with auth token and user info after
  • a successful auth flow and redirect. *
  • Here is our opportunity to:
  • 1. Create a userId that is unique to our system based on userInfo
  • 2. Set the right session cookies from this.

func (*OneAuth) StartLinkOAuth

func (a *OneAuth) StartLinkOAuth(r *http.Request, userID string)

StartLinkOAuth initiates OAuth account linking by storing the user ID in session. Call this from your "Link [Provider] Account" button handler.

Example Usage

func handleLinkGoogle(w http.ResponseWriter, r *http.Request) {
    userID := getLoggedInUserID(r)
    oneAuth.StartLinkOAuth(r, userID)
    // Redirect to Google OAuth
    http.Redirect(w, r, "/auth/google/", http.StatusFound)
}

type SecurityHeadersConfig added in v0.0.43

type SecurityHeadersConfig struct {
	// HSTS max-age in seconds. Set to 0 to disable. Default: 31536000 (1 year).
	HSTSMaxAge int
	// Include subdomains in HSTS. Default: true.
	HSTSIncludeSubDomains bool
	// X-Frame-Options value. Default: "DENY". Set to "" to disable.
	FrameOptions string
	// Content-Security-Policy value. Default: "default-src 'self'". Set to "" to disable.
	ContentSecurityPolicy string
	// Referrer-Policy value. Default: "strict-origin-when-cross-origin". Set to "" to disable.
	ReferrerPolicy string
	// Permissions-Policy value. Default: disables camera, mic, geo. Set to "" to disable.
	PermissionsPolicy string
	// Cross-Origin-Embedder-Policy value. Default: "credentialless". Set to "" to disable.
	CrossOriginEmbedderPolicy string
	// Cross-Origin-Opener-Policy value. Default: "same-origin". Set to "" to disable.
	CrossOriginOpenerPolicy string
	// Cross-Origin-Resource-Policy value. Default: "same-origin". Set to "" to disable.
	CrossOriginResourcePolicy string
}

SecurityHeadersConfig controls which security headers are set.

func DefaultSecurityHeadersConfig added in v0.0.43

func DefaultSecurityHeadersConfig() SecurityHeadersConfig

DefaultSecurityHeadersConfig returns secure defaults.

Jump to

Keyboard shortcuts

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