jawsauth

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2026 License: MIT Imports: 25 Imported by: 1

README

build coverage goreport Docs

jawsauth

OIDC-verified authentication for JaWS sessions.

  • Requires an OIDC-compliant provider.
  • Uses OIDC discovery from the configured issuer.
  • Verifies id_token and stores identity claims in session data.
  • Adds PKCE (S256) and OIDC nonce verification to the authorization-code flow.
  • Automatically refreshes the id_token in the background before it expires.
  • Supports admin-only handlers: Wrap/Handler for any authenticated user, WrapAdmin/HandlerAdmin gated by SetAdmins.

Documentation

Overview

Package jawsauth provides OIDC-verified authentication for JaWS HTTP sessions.

It uses OIDC discovery from a configured issuer to run the OAuth2 authorization-code flow with PKCE and nonce verification, verifies the returned id_token, and stores the identity claims in the JaWS session. It also refreshes the id_token in the background before it expires and supports gating handlers to administrator emails.

Create a Server with New (or NewDebug) and protect handlers with Server.Wrap, Server.WrapAdmin, Server.Handler or Server.HandlerAdmin.

Index

Constants

This section is empty.

Variables

View Source
var ErrConfig errConfig

ErrConfig matches all configuration validation errors.

View Source
var ErrConfigIssuerMustBeHTTPS = errors.New("issuer url must use https")

ErrConfigIssuerMustBeHTTPS means Issuer must use the https scheme unless AllowInsecureIssuer is enabled.

View Source
var ErrConfigMissingValue = errors.New("config value is missing")

ErrConfigMissingValue means a required configuration value is missing.

View Source
var ErrConfigURLMissingHost = errors.New("url host is missing")

ErrConfigURLMissingHost means a configured URL does not include a host.

View Source
var ErrConfigURLNotAbsolute = errors.New("url is not absolute")

ErrConfigURLNotAbsolute means a configured URL is not absolute.

View Source
var ErrOAuth2Callback = errors.New("oauth2 callback error")

ErrOAuth2Callback matches OAuth2 callback errors returned by the identity provider.

View Source
var ErrOAuth2MissingPKCEVerifier = errors.New("oauth2 missing pkce verifier")

ErrOAuth2MissingPKCEVerifier means the callback session did not contain the required PKCE verifier.

View Source
var ErrOAuth2MissingSession = errors.New("oauth2 missing session")

ErrOAuth2MissingSession means no jaws session was available to carry the OAuth2 flow state.

View Source
var ErrOAuth2MissingState = errors.New("oauth2 missing state")

ErrOAuth2MissingState means the callback session did not contain the expected state value.

View Source
var ErrOAuth2NotConfigured = errors.New("oauth2 not configured")

ErrOAuth2NotConfigured means OAuth2/OIDC is not configured on the Server.

View Source
var ErrOAuth2WrongState = errors.New("oauth2 wrong state")

ErrOAuth2WrongState means the callback state value did not match the stored session state.

View Source
var ErrOIDCDiscovery = errors.New("oidc discovery failed")

ErrOIDCDiscovery means OIDC provider discovery failed.

View Source
var ErrOIDCInvalidIDToken = errors.New("oidc invalid id_token")

ErrOIDCInvalidIDToken means id_token verification failed.

View Source
var ErrOIDCMissingIDToken = errors.New("oidc missing id_token")

ErrOIDCMissingIDToken means the token response did not include an id_token.

View Source
var ErrOIDCMissingNonce = errors.New("oidc missing nonce")

ErrOIDCMissingNonce means the login request did not include a nonce.

View Source
var ErrOIDCNonceMismatch = errors.New("oidc nonce mismatch")

ErrOIDCNonceMismatch means the id_token nonce did not match the stored session nonce.

View Source
var ErrOIDCProviderMetadata = errors.New("oidc provider metadata invalid")

ErrOIDCProviderMetadata means discovered OIDC metadata was invalid.

View Source
var ErrServerNilJaws = errors.New("jawsauth: nil *jaws.Jaws")

ErrServerNilJaws is returned by New and NewDebug when the *jaws.Jaws argument is nil. Server methods dereference Server.Jaws and require it to be non-nil for the lifetime of the Server.

View Source
var ErrUserInfoStatus = errors.New("userinfo status")

ErrUserInfoStatus means the UserInfo endpoint returned a non-200 HTTP status.

View Source
var SetHeaders = DefaultSetHeaders

SetHeaders writes the HTTP response headers for all OAuth endpoint responses.

It defaults to DefaultSetHeaders and may be reassigned at startup to customize headers; it must not be reassigned concurrently with serving requests.

Functions

func DefaultSetHeaders added in v1.0.7

func DefaultSetHeaders(hw http.ResponseWriter, ishttps bool)

DefaultSetHeaders writes response headers for OAuth endpoint responses.

Types

type Config

type Config struct {
	RedirectURL string // required. e.g. "https://application.example.com/oauth2/callback"
	Issuer      string // required. e.g. "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0"
	AuthURL     string // optional override for discovered authorization_endpoint
	TokenURL    string // optional override for discovered token_endpoint
	UserInfoURL string // optional override for discovered userinfo_endpoint
	// AllowInsecureIssuer permits "http://" Issuer URLs and should only be used for tests/dev.
	AllowInsecureIssuer bool
	// HTTPClient is used for OIDC discovery at startup and, unless a per-request
	// oauth2.HTTPClient is supplied via the request context, as the default client
	// for token exchange/refresh and UserInfo requests.
	HTTPClient *http.Client
	Scopes     []string // optional additional scopes, "openid" and "email" are always ensured
	ClientID   string
	//gosec:disable G117
	ClientSecret string
}

Config holds the OIDC/OAuth2 settings used by New and NewDebug to construct a Server.

RedirectURL, Issuer and ClientID are required; AuthURL, TokenURL and UserInfoURL override values otherwise obtained via OIDC discovery, and the remaining fields are optional.

func (*Config) Validate

func (cfg *Config) Validate() (err error)

type EventFunc added in v0.3.0

type EventFunc func(sess *jaws.Session, hr *http.Request)

EventFunc is called for login and logout lifecycle events.

For a LogoutEvent triggered by an auth-refresh timer rather than an HTTP request, hr may be nil.

type FailedFunc added in v0.9.0

type FailedFunc func(hw http.ResponseWriter, hr *http.Request, httpCode int, err error, email string) (wroteresponse bool)

FailedFunc is called when a login attempt fails.

It returns true if it wrote the HTTP response itself, in which case jawsauth writes nothing further.

type HandleFunc

type HandleFunc func(uri string, handler http.Handler)

HandleFunc registers handler to serve requests for the given URI path.

It matches the shape of http.ServeMux.Handle and is supplied to New and NewDebug so the login, logout and callback endpoints can be wired into the caller's router.

type JawsAuth added in v0.6.0

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

JawsAuth exposes authenticated session data to JaWS templates. Its zero value is safe to use and reports no user data.

func (*JawsAuth) Data added in v0.6.0

func (a *JawsAuth) Data() (x map[string]any)

Data returns the verified OIDC claims stored in the session, or nil. It is safe to call on a nil or zero-value JawsAuth.

func (*JawsAuth) Email added in v0.6.0

func (a *JawsAuth) Email() (s string)

Email returns the authenticated email stored in the session, or an empty string. It is safe to call on a nil or zero-value JawsAuth.

func (*JawsAuth) EmailVerified added in v1.0.9

func (a *JawsAuth) EmailVerified() (yes bool)

EmailVerified returns whether the authenticated email was marked verified. It is safe to call on a nil or zero-value JawsAuth.

func (*JawsAuth) IsAdmin added in v0.6.0

func (a *JawsAuth) IsAdmin() (yes bool)

IsAdmin reports whether the authenticated email is an administrator. A nil or zero-value JawsAuth follows Server.IsAdmin's nil-server behavior and returns true.

type OAuth2CallbackError added in v1.0.0

type OAuth2CallbackError struct {
	Code        string // OAuth2 error code from the callback.
	Description string // Optional error description from the callback.
	URI         string // Optional URI with details about the callback error.
}

OAuth2CallbackError describes an OAuth2 callback error response.

func (*OAuth2CallbackError) Error added in v1.0.0

func (err *OAuth2CallbackError) Error() string

func (*OAuth2CallbackError) Is added in v1.0.0

func (err *OAuth2CallbackError) Is(target error) bool

type Server

type Server struct {
	Jaws *jaws.Jaws
	//gosec:disable G117
	SessionKey              string                  // default is "oidc_claims", value will be of type map[string]any // #nosec G117
	SessionTokenKey         string                  // default is "oauth2_tokensource", value will be of type oauth2.TokenSource
	SessionEmailKey         string                  // default is "email", value will be of type string
	SessionEmailVerifiedKey string                  // default is "email_verified", value will be of type bool
	HandledPaths            map[string]struct{}     // URI paths we have registered handlers for
	LoginEvent              EventFunc               // if not nil, called after a successful login
	LogoutEvent             EventFunc               // if not nil, called before logout; hr may be nil for timer-driven logout
	LoginFailed             FailedFunc              // if not nil, called on failed login
	Options                 []oauth2.AuthCodeOption // options to use, see https://pkg.go.dev/golang.org/x/oauth2#AuthCodeOption
	// contains filtered or unexported fields
}

Server provides OIDC-verified authentication for JaWS sessions.

Create one with New or NewDebug. Its methods are safe for concurrent use; the exported configuration fields and callbacks should be set before serving requests.

func New

func New(jw *jaws.Jaws, cfg *Config, handleFn HandleFunc) (srv *Server, err error)

New creates a Server providing OIDC-verified authentication for JaWS sessions.

It configures the Server from cfg and registers the login, logout and OAuth2 callback endpoints via handleFn. A nil jw returns ErrServerNilJaws. Use Valid to test whether OIDC authentication was successfully configured.

func NewDebug added in v0.2.0

func NewDebug(jw *jaws.Jaws, cfg *Config, handleFn HandleFunc, overrideUrl string) (srv *Server, err error)

NewDebug behaves like New but can override the scheme and host of cfg.RedirectURL.

overrideUrl supplies the replacement scheme and host (an empty overrideUrl disables the override), which is useful when serving behind a different public address during development.

A nil jw returns ErrServerNilJaws and a nil Server. Otherwise a non-nil Server is always returned. OIDC is configured, and the login, logout and callback handlers registered via handleFn, only when cfg, handleFn and cfg.RedirectURL are all provided; any error from OIDC discovery is returned alongside the not-yet-Valid Server.

func (*Server) GetAdmins added in v0.6.0

func (srv *Server) GetAdmins() (emails []string)

GetAdmins returns a sorted list of the administrator emails. If empty, everyone is considered an administrator.

func (*Server) HandleAuthResponse

func (srv *Server) HandleAuthResponse(hw http.ResponseWriter, hr *http.Request)

HandleAuthResponse handles the OIDC redirect/callback endpoint.

For GET requests it validates the state, exchanges the authorization code using the stored PKCE verifier, verifies the id_token and its nonce, stores the verified claims in the session, and invokes LoginEvent on success or LoginFailed on failure. Non-GET requests receive 405.

func (*Server) HandleLogin

func (srv *Server) HandleLogin(hw http.ResponseWriter, hr *http.Request)

HandleLogin begins the OIDC login flow.

For GET requests it generates and stores the state, nonce and PKCE verifier in the session, then responds with a 302 redirect to the provider's authorization URL. Non-GET requests receive 405.

func (*Server) HandleLogout

func (srv *Server) HandleLogout(hw http.ResponseWriter, hr *http.Request)

HandleLogout clears the session's stored authentication and redirects.

For GET requests it clears the auth (firing LogoutEvent if set) and responds with a 302 redirect back to the sanitized referrer (or "/"). Non-GET requests receive 405.

func (*Server) Handler

func (srv *Server) Handler(name string, dot any) http.Handler

Handler returns a http.Handler that renders the named jaws.Template with dot and requires an authenticated user.

Unauthenticated requests are redirected into the OIDC login flow (HandleLogin), which verifies the id_token and stores the claims in srv.SessionKey (with optional UserInfo fallback) before the user returns. If the Server is not Valid, the template handler is returned without the authentication requirement.

func (*Server) HandlerAdmin added in v0.6.0

func (srv *Server) HandlerAdmin(name string, dot any) http.Handler

HandlerAdmin returns a http.Handler that renders the named jaws.Template with dot and requires an authenticated administrator.

Unauthenticated requests are redirected into the OIDC login flow (HandleLogin); authenticated non-admins (see SetAdmins and IsAdmin) are served the 403 handler. If the Server is not Valid, the template handler is returned without the authentication requirement.

func (*Server) IsAdmin added in v0.6.0

func (srv *Server) IsAdmin(email string) (yes bool)

IsAdmin returns true if email belongs to an admin, if the list of admins is empty, or if srv is nil.

func (*Server) Logout added in v1.2.0

func (srv *Server) Logout(sess *jaws.Session, hr *http.Request) (cleared bool)

Logout clears all authentication state for the session and returns true if anything was cleared.

It stops the auth-refresh timer, clears the OIDC claims, token source, email, expiry and any in-flight OAuth flow keys, calls LogoutEvent (if set), and marks the session dirty. It performs no HTTP redirect, so the caller can build its own post-logout response (for example an RP-initiated end-session redirect). It is safe to call with a nil receiver or nil session.

func (*Server) Set403Handler added in v0.6.0

func (srv *Server) Set403Handler(h http.Handler)

Set403Handler sets the handler used to serve 403 Forbidden responses to authenticated non-admin users.

A nil h restores the default handler. It is safe for concurrent use.

func (*Server) SetAdmins added in v0.6.0

func (srv *Server) SetAdmins(emails []string)

SetAdmins sets the emails of administrators. If empty, everyone is considered an administrator.

func (*Server) Valid added in v0.2.0

func (srv *Server) Valid() bool

Valid returns true if OIDC authentication is configured.

func (*Server) Wrap

func (srv *Server) Wrap(h http.Handler) (rh http.Handler)

Wrap returns a http.Handler that requires an authenticated user before invoking h.

Unauthenticated requests are redirected into the OIDC login flow (HandleLogin), which verifies the id_token and stores the claims in srv.SessionKey (with optional UserInfo fallback) before the user returns. If the Server is not Valid, returns h.

func (*Server) WrapAdmin added in v0.6.0

func (srv *Server) WrapAdmin(h http.Handler) (rh http.Handler)

WrapAdmin returns a http.Handler that requires an authenticated administrator before invoking h.

Unauthenticated requests are redirected into the OIDC login flow (HandleLogin); authenticated users whose email is not an admin (see SetAdmins and IsAdmin) are served the 403 handler instead of h. If the Server is not Valid, returns h.

Directories

Path Synopsis
cmd
demo command

Jump to

Keyboard shortcuts

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